mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-23 10:07:19 +00:00
Restore encrypted TiddlyWiki support
This commit is contained in:
parent
d4da6d4ced
commit
a9de17bd55
23
bld.sh
23
bld.sh
@ -21,28 +21,35 @@ echo "Using TW5_BUILD_OUTPUT as [$TW5_BUILD_OUTPUT]"
|
|||||||
|
|
||||||
echo "five.tiddlywiki.com" > $TW5_BUILD_OUTPUT/CNAME
|
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 \
|
node ../../tiddlywiki.js \
|
||||||
--verbose \
|
--verbose \
|
||||||
--password password \
|
--password password \
|
||||||
--savetiddler ReadMe ../../readme.md text/html \
|
--savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/encrypted.html text/plain \
|
||||||
--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 \
|
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
|
|
||||||
# Second, empty.html: empty wiki for reuse
|
# Third, empty.html: empty wiki for reuse
|
||||||
|
|
||||||
pushd editions/empty > /dev/null
|
pushd editions/empty > /dev/null
|
||||||
|
|
||||||
node ../../tiddlywiki.js \
|
node ../../tiddlywiki.js \
|
||||||
--verbose \
|
--verbose \
|
||||||
--password password \
|
|
||||||
--savetiddler $:/core/templates/tiddlywiki5.template.html $TW5_BUILD_OUTPUT/empty.html text/plain \
|
--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
|
|| exit 1
|
||||||
|
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
|
49
core/boot.js
49
core/boot.js
@ -358,7 +358,10 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
|||||||
this.setWrapperDisplay();
|
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() {
|
$tw.utils.Crypto = function() {
|
||||||
var sjcl = $tw.browser ? window.sjcl : require("./sjcl.js"),
|
var sjcl = $tw.browser ? window.sjcl : require("./sjcl.js"),
|
||||||
password = null,
|
password = null,
|
||||||
@ -374,7 +377,14 @@ $tw.utils.Crypto = function() {
|
|||||||
};
|
};
|
||||||
this.setPassword = function(newPassword) {
|
this.setPassword = function(newPassword) {
|
||||||
password = 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) {
|
this.encrypt = function(text) {
|
||||||
return callSjcl("encrypt",text);
|
return callSjcl("encrypt",text);
|
||||||
};
|
};
|
||||||
@ -723,22 +733,13 @@ $tw.wiki = new $tw.Wiki();
|
|||||||
if($tw.browser) {
|
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) {
|
$tw.boot.decryptEncryptedTiddlers = function(callback) {
|
||||||
var encryptedArea = document.getElementById("encryptedArea"),
|
var encryptedArea = document.getElementById("encryptedStoreArea");
|
||||||
encryptedTiddlers = [];
|
|
||||||
if(encryptedArea) {
|
if(encryptedArea) {
|
||||||
for(var t = 0; t <encryptedArea.childNodes.length; t++) {
|
var encryptedText = encryptedArea.innerHTML;
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Prompt for the password
|
// Prompt for the password
|
||||||
$tw.passwordPrompt.createPrompt({
|
$tw.passwordPrompt.createPrompt({
|
||||||
serviceName: "Enter a password to decrypt this TiddlyWiki",
|
serviceName: "Enter a password to decrypt this TiddlyWiki",
|
||||||
@ -747,18 +748,12 @@ $tw.boot.decryptEncryptedTiddlers = function(callback) {
|
|||||||
callback: function(data) {
|
callback: function(data) {
|
||||||
// Attempt to decrypt the tiddlers
|
// Attempt to decrypt the tiddlers
|
||||||
$tw.crypto.setPassword(data.password);
|
$tw.crypto.setPassword(data.password);
|
||||||
for(var t=encryptedTiddlers.length-1; t>=0; t--) {
|
var decryptedText = $tw.crypto.decrypt(encryptedText);
|
||||||
var decrypted = $tw.crypto.decrypt(encryptedTiddlers[t]);
|
if(decryptedText) {
|
||||||
if(decrypted) {
|
var json = JSON.parse(decryptedText);
|
||||||
var json = JSON.parse(decrypted);
|
for(var title in json) {
|
||||||
for(var title in json) {
|
$tw.preloadTiddler(json[title]);
|
||||||
$tw.preloadTiddler(json[title]);
|
|
||||||
}
|
|
||||||
encryptedTiddlers.splice(t,1);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Check if we're all done
|
|
||||||
if(encryptedTiddlers.length === 0) {
|
|
||||||
// Call the callback
|
// Call the callback
|
||||||
callback();
|
callback();
|
||||||
// Exit and remove the password prompt
|
// Exit and remove the password prompt
|
||||||
@ -770,7 +765,7 @@ $tw.boot.decryptEncryptedTiddlers = function(callback) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} 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();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1094,6 +1089,8 @@ $tw.boot.startup = function() {
|
|||||||
$tw.wiki.defineTiddlerModules();
|
$tw.wiki.defineTiddlerModules();
|
||||||
// And any modules within bundles
|
// And any modules within bundles
|
||||||
$tw.wiki.defineBundledModules();
|
$tw.wiki.defineBundledModules();
|
||||||
|
// Make sure the crypto state tiddler is up to date
|
||||||
|
$tw.crypto.updateCryptoStateTiddler();
|
||||||
// Run any startup modules
|
// Run any startup modules
|
||||||
$tw.modules.forEachModuleOfType("startup",function(title,module) {
|
$tw.modules.forEachModuleOfType("startup",function(title,module) {
|
||||||
if(module.startup) {
|
if(module.startup) {
|
||||||
|
@ -82,6 +82,21 @@ exports.startup = function() {
|
|||||||
downloadType: "text/plain"
|
downloadType: "text/plain"
|
||||||
});
|
});
|
||||||
},false);
|
},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
|
// Apply stylesheets
|
||||||
var styleTiddlers = $tw.wiki.getTiddlersWithTag("$:/core/styles");
|
var styleTiddlers = $tw.wiki.getTiddlersWithTag("$:/core/styles");
|
||||||
$tw.utils.each(styleTiddlers,function(title) {
|
$tw.utils.each(styleTiddlers,function(title) {
|
||||||
|
51
core/modules/widgets/encrypt.js
Normal file
51
core/modules/widgets/encrypt.js
Normal 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;
|
||||||
|
|
||||||
|
})();
|
@ -5,6 +5,7 @@ title: $:/templates/PageTemplate
|
|||||||
|
|
||||||
<!-- The page header -->
|
<!-- The page header -->
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
|
{{$:/snippets/encryptionstatus}}
|
||||||
<$button message="tw-NewTiddler" class="btn btn-mini btn-success">New</$button>
|
<$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>
|
<$button message="tw-save-wiki" class="btn btn-mini btn-primary">Save</$button>
|
||||||
</div>
|
</div>
|
||||||
|
13
core/templates/store.area.template.html.tid
Normal file
13
core/templates/store.area.template.html.tid
Normal 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>
|
@ -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}}}
|
{{{ [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>
|
</div>
|
||||||
<!----------- Ordinary tiddlers ----------->
|
<!----------- Ordinary tiddlers ----------->
|
||||||
<div id="storeArea" style="display:none;">
|
{{$:/core/templates/store.area.template.html}}
|
||||||
{{{ [!is[shadow]] ||$:/core/templates/html-div-tiddler}}}
|
|
||||||
</div>
|
|
||||||
<!----------- Library modules ----------->
|
<!----------- Library modules ----------->
|
||||||
<div id="libraryModules" style="display:none;">
|
<div id="libraryModules" style="display:none;">
|
||||||
{{$:/core/lib/jquery.min.js||$:/core/templates/javascript-tiddler}}
|
{{$:/core/lib/jquery.min.js||$:/core/templates/javascript-tiddler}}
|
||||||
|
11
core/wiki/encryptionstatus.tid
Normal file
11
core/wiki/encryptionstatus.tid
Normal 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>
|
@ -28,6 +28,7 @@ Internally, TiddlyWiki is built on a number of key objects and mechanisms:
|
|||||||
* SyncMechanism
|
* SyncMechanism
|
||||||
* CommandMechanism
|
* CommandMechanism
|
||||||
* ConfigMechanism
|
* ConfigMechanism
|
||||||
|
* EncryptionMechanism
|
||||||
|
|
||||||
! Plugin Module Types
|
! Plugin Module Types
|
||||||
|
|
||||||
|
14
editions/tw5.com/tiddlers/mechanisms/EncryptionMechanism.tid
Normal file
14
editions/tw5.com/tiddlers/mechanisms/EncryptionMechanism.tid
Normal 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
|
Loading…
Reference in New Issue
Block a user