From a9de17bd553c1150a7c5f1bb04b3e1643020d157 Mon Sep 17 00:00:00 2001 From: Jeremy Ruston Date: Thu, 31 Jan 2013 10:20:13 +0000 Subject: [PATCH] Restore encrypted TiddlyWiki support --- bld.sh | 23 ++++++--- core/boot.js | 49 +++++++++--------- core/modules/startup.js | 15 ++++++ core/modules/widgets/encrypt.js | 51 +++++++++++++++++++ core/templates/PageTemplate.tid | 1 + core/templates/store.area.template.html.tid | 13 +++++ core/templates/tiddlywiki5.template.html.tid | 4 +- core/wiki/encryptionstatus.tid | 11 ++++ editions/tw5.com/tiddlers/Internals.tid | 1 + .../mechanisms/EncryptionMechanism.tid | 14 +++++ 10 files changed, 145 insertions(+), 37 deletions(-) create mode 100644 core/modules/widgets/encrypt.js create mode 100644 core/templates/store.area.template.html.tid create mode 100644 core/wiki/encryptionstatus.tid create mode 100644 editions/tw5.com/tiddlers/mechanisms/EncryptionMechanism.tid diff --git a/bld.sh b/bld.sh index d925f1621..002377747 100755 --- a/bld.sh +++ b/bld.sh @@ -21,28 +21,35 @@ echo "Using TW5_BUILD_OUTPUT as [$TW5_BUILD_OUTPUT]" echo "five.tiddlywiki.com" > $TW5_BUILD_OUTPUT/CNAME -# First, index.html: the main file, including content +# First, +# readme.md: the readme file for GitHub +# index.html: the main file, including content +# static.html: the static version of the default tiddlers + +node ../../tiddlywiki.js \ + --verbose \ + --savetiddler ReadMe ../../readme.md text/html \ + --savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/index.html text/plain \ + --savetiddler $:/core/templates/static.template.html $TW5_BUILD_OUTPUT/static.html text/plain \ + || exit 1 + +# Second, encrypted.html: a version of the main file encrypted with the password "password" node ../../tiddlywiki.js \ --verbose \ --password password \ - --savetiddler ReadMe ../../readme.md text/html \ - --savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/index.html text/plain \ - --savetiddler $:/core/templates/tiddlywiki5.encrypted.template.html $TW5_BUILD_OUTPUT/encrypted.html text/plain \ - --savetiddler $:/core/templates/static.template.html $TW5_BUILD_OUTPUT/static.html text/plain \ + --savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/encrypted.html text/plain \ || exit 1 popd > /dev/null -# Second, empty.html: empty wiki for reuse +# Third, empty.html: empty wiki for reuse pushd editions/empty > /dev/null node ../../tiddlywiki.js \ --verbose \ - --password password \ --savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/empty.html text/plain \ - --savetiddler $:/core/templates/tiddlywiki5.encrypted.template.html $TW5_BUILD_OUTPUT/empty_encrypted.html text/plain \ || exit 1 popd > /dev/null diff --git a/core/boot.js b/core/boot.js index df6ee3049..c1a772fa4 100644 --- a/core/boot.js +++ b/core/boot.js @@ -358,7 +358,10 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) { this.setWrapperDisplay(); }; -// Crypto helper object for encrypted content +/* +Crypto helper object for encrypted content. It maintains the password text in a closure, and provides methods to change +the password, and to encrypt/decrypt a block of text +*/ $tw.utils.Crypto = function() { var sjcl = $tw.browser ? window.sjcl : require("./sjcl.js"), password = null, @@ -374,7 +377,14 @@ $tw.utils.Crypto = function() { }; this.setPassword = function(newPassword) { password = newPassword; + this.updateCryptoStateTiddler(); }; + this.updateCryptoStateTiddler = function() { + $tw.wiki.addTiddler(new $tw.Tiddler({title: "$:/isEncrypted", text: password ? "yes" : "no"})); + }; + this.hasPassword = function() { + return !!password; + } this.encrypt = function(text) { return callSjcl("encrypt",text); }; @@ -723,22 +733,13 @@ $tw.wiki = new $tw.Wiki(); if($tw.browser) { /* -Get any encrypted tiddlers +Decrypt any tiddlers stored within the element with the ID "encryptedArea". The function is asynchronous to allow the user to be prompted for a password + callback: function to be called the decryption is complete */ $tw.boot.decryptEncryptedTiddlers = function(callback) { - var encryptedArea = document.getElementById("encryptedArea"), - encryptedTiddlers = []; + var encryptedArea = document.getElementById("encryptedStoreArea"); if(encryptedArea) { - for(var t = 0; t =0; t--) { - var decrypted = $tw.crypto.decrypt(encryptedTiddlers[t]); - if(decrypted) { - var json = JSON.parse(decrypted); - for(var title in json) { - $tw.preloadTiddler(json[title]); - } - encryptedTiddlers.splice(t,1); + var decryptedText = $tw.crypto.decrypt(encryptedText); + if(decryptedText) { + var json = JSON.parse(decryptedText); + for(var title in json) { + $tw.preloadTiddler(json[title]); } - } - // Check if we're all done - if(encryptedTiddlers.length === 0) { // Call the callback callback(); // Exit and remove the password prompt @@ -770,7 +765,7 @@ $tw.boot.decryptEncryptedTiddlers = function(callback) { } }); } else { - // Just invoke the callback straight away if there wasn't any encrypted tiddlers + // Just invoke the callback straight away if there weren't any encrypted tiddlers callback(); } }; @@ -1094,6 +1089,8 @@ $tw.boot.startup = function() { $tw.wiki.defineTiddlerModules(); // And any modules within bundles $tw.wiki.defineBundledModules(); + // Make sure the crypto state tiddler is up to date + $tw.crypto.updateCryptoStateTiddler(); // Run any startup modules $tw.modules.forEachModuleOfType("startup",function(title,module) { if(module.startup) { diff --git a/core/modules/startup.js b/core/modules/startup.js index a86b74d6b..3ebfbaf91 100644 --- a/core/modules/startup.js +++ b/core/modules/startup.js @@ -82,6 +82,21 @@ exports.startup = function() { downloadType: "text/plain" }); },false); + // Install the crypto event handler + document.addEventListener("tw-set-password",function(event) { + $tw.passwordPrompt.createPrompt({ + serviceName: "Set new password for this TiddlyWiki", + noUserName: true, + submitText: "Set password", + callback: function(data) { + $tw.crypto.setPassword(data.password); + return true; // Get rid of the password prompt + } + }); + }); + document.addEventListener("tw-clear-password",function(event) { + $tw.crypto.setPassword(null); + }); // Apply stylesheets var styleTiddlers = $tw.wiki.getTiddlersWithTag("$:/core/styles"); $tw.utils.each(styleTiddlers,function(title) { diff --git a/core/modules/widgets/encrypt.js b/core/modules/widgets/encrypt.js new file mode 100644 index 000000000..e5fe4dd0c --- /dev/null +++ b/core/modules/widgets/encrypt.js @@ -0,0 +1,51 @@ +/*\ +title: $:/core/modules/widget/encrypt.js +type: application/javascript +module-type: widget + +Implements the encrypt widget. + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +var EncryptWidget = function(renderer) { + // Save state + this.renderer = renderer; + // Generate child nodes + this.generate(); +}; + +EncryptWidget.prototype.generate = function() { + // Get the parameters from the attributes + this.filter = this.renderer.getAttribute("filter"); + // Check whether we've got an encryption password + var isEncrypted = $tw.crypto.hasPassword(); + // Encrypt the filtered tiddlers + var tiddlers = this.renderer.renderTree.wiki.filterTiddlers(this.filter), + json = {}, + self = this; + $tw.utils.each(tiddlers,function(title) { + var tiddler = self.renderer.renderTree.wiki.getTiddler(title), + jsonTiddler = {}; + for(var f in tiddler.fields) { + jsonTiddler[f] = tiddler.getFieldString(f); + } + json[title] = jsonTiddler; + }); + var encryptedText = $tw.utils.htmlEncode($tw.crypto.encrypt(JSON.stringify(json))); + // Set the return element + this.tag = "pre"; + this.attributes ={"class": "tw-encrypt"}; + this.children = this.renderer.renderTree.createRenderers(this.renderer.renderContext,[{ + type: "text", + text: encryptedText + }]); +}; + +exports.encrypt = EncryptWidget; + +})(); diff --git a/core/templates/PageTemplate.tid b/core/templates/PageTemplate.tid index c244e159e..004ca2312 100644 --- a/core/templates/PageTemplate.tid +++ b/core/templates/PageTemplate.tid @@ -5,6 +5,7 @@ title: $:/templates/PageTemplate
+{{$:/snippets/encryptionstatus}} <$button message="tw-NewTiddler" class="btn btn-mini btn-success">New <$button message="tw-save-wiki" class="btn btn-mini btn-primary">Save
diff --git a/core/templates/store.area.template.html.tid b/core/templates/store.area.template.html.tid new file mode 100644 index 000000000..2a930be1a --- /dev/null +++ b/core/templates/store.area.template.html.tid @@ -0,0 +1,13 @@ +title: $:/core/templates/store.area.template.html + +<$reveal type="nomatch" state="$:/isEncrypted" text="yes"> +`` + +<$reveal type="match" state="$:/isEncrypted" text="yes"> +`` +`` + \ No newline at end of file diff --git a/core/templates/tiddlywiki5.template.html.tid b/core/templates/tiddlywiki5.template.html.tid index 72a380420..373ea734d 100644 --- a/core/templates/tiddlywiki5.template.html.tid +++ b/core/templates/tiddlywiki5.template.html.tid @@ -34,9 +34,7 @@ title: $:/core/templates/tiddlywiki5.template.html {{{ [is[shadow]] -[type[text/css]] -[type[application/javascript]has[module-type]] -[type[application/javascript]library[yes]] -[[$:/core/boot.js]] -[[$:/core/bootprefix.js]] ||$:/core/templates/html-div-tiddler}}} - +{{$:/core/templates/store.area.template.html}}