1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-06-14 17:39:56 +00:00

Restore encrypted TiddlyWiki support

This commit is contained in:
Jeremy Ruston 2013-01-31 10:20:13 +00:00
parent d4da6d4ced
commit a9de17bd55
10 changed files with 145 additions and 37 deletions

23
bld.sh
View File

@ -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

View File

@ -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 <encryptedArea.childNodes.length; t++) {
var childNode = encryptedArea.childNodes[t];
if(childNode.hasAttribute && childNode.hasAttribute("data-tw-encrypted-tiddlers")) {
var e = childNode.firstChild;
while(e && e.nodeName.toLowerCase() !== "pre") {
e = e.nextSibling;
}
encryptedTiddlers.push($tw.utils.htmlDecode(e.innerHTML));
}
}
var encryptedText = encryptedArea.innerHTML;
// Prompt for the password
$tw.passwordPrompt.createPrompt({
serviceName: "Enter a password to decrypt this TiddlyWiki",
@ -747,18 +748,12 @@ $tw.boot.decryptEncryptedTiddlers = function(callback) {
callback: function(data) {
// Attempt to decrypt the tiddlers
$tw.crypto.setPassword(data.password);
for(var t=encryptedTiddlers.length-1; 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) {

View File

@ -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) {

View File

@ -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;
})();

View File

@ -5,6 +5,7 @@ title: $:/templates/PageTemplate
<!-- The page header -->
<div class="pull-right">
{{$:/snippets/encryptionstatus}}
<$button message="tw-NewTiddler" class="btn btn-mini btn-success">New</$button>
<$button message="tw-save-wiki" class="btn btn-mini btn-primary">Save</$button>
</div>

View File

@ -0,0 +1,13 @@
title: $:/core/templates/store.area.template.html
<$reveal type="nomatch" state="$:/isEncrypted" text="yes">
`<div id="storeArea" style="display:none;">`
{{{ [!is[shadow]] ||$:/core/templates/html-div-tiddler}}}
`</div>`
</$reveal>
<$reveal type="match" state="$:/isEncrypted" text="yes">
`<!------------- Encrypted tiddlers --------->`
`<pre id="encryptedStoreArea" type="text/plain" style="display:none;">`
<$encrypt filter="[!is[shadow]]"/>
`</pre>`
</$reveal>

View File

@ -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}}}
</div>
<!----------- Ordinary tiddlers ----------->
<div id="storeArea" style="display:none;">
{{{ [!is[shadow]] ||$:/core/templates/html-div-tiddler}}}
</div>
{{$:/core/templates/store.area.template.html}}
<!----------- Library modules ----------->
<div id="libraryModules" style="display:none;">
{{$:/core/lib/jquery.min.js||$:/core/templates/javascript-tiddler}}

View File

@ -0,0 +1,11 @@
title: $:/snippets/encryptionstatus
<$reveal type="match" state="$:/isEncrypted" text="yes">
This wiki is encrypted.
<$button message="tw-clear-password">Clear password</$button>
<$button message="tw-set-password">Change password</$button>
</$reveal>
<$reveal type="nomatch" state="$:/isEncrypted" text="yes">
This wiki is not encrypted.
<$button message="tw-set-password">Set password</$button>
</$reveal>

View File

@ -28,6 +28,7 @@ Internally, TiddlyWiki is built on a number of key objects and mechanisms:
* SyncMechanism
* CommandMechanism
* ConfigMechanism
* EncryptionMechanism
! Plugin Module Types

View File

@ -0,0 +1,14 @@
title: EncryptionMechanism
tags: docs mechanism
TiddlyWiki5 allows the entire content of a TiddlyWiki HTML file to be encrypted with the Stanford JavaScript Crypto Library. Opening an encrypted TiddlyWiki in the browser prompts for a password before decrypting and displaying the content.
The EncryptionMechanism is implemented with the following elements:
* A crypto "password vault" within the BootMechanism that holds the current encryption password
* The ability of the BootMechanism to read a block of encrypted tiddlers from the TiddlyWiki file, to prompt the user for a password, and to decrypt the tiddlers
* Handlers for the messages SetPasswordMessage and ClearPasswordMessage that handle the user interface for password changes
* The `<$encrypt>` widget within the main file template that encrypts a filtered list of tiddlers with the currently held password
* The [[$:/isEncrypted]] tiddler that contains "yes" or "no" according to whether there is a password in the password vault
** The availability of this tiddler allows the RevealWidget to be used to selectively display user interface elements according to whether encryption is in force
* The [[$:/snippets/encryptionstatus]] snippet that displays the current encryption status