mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-26 19:47:20 +00:00
Add support for importing encrypted TiddlyWiki documents
This commit is contained in:
parent
2f4932fefc
commit
299e9d15fb
@ -58,3 +58,7 @@ Error message and password prompt
|
||||
line-height: 20px;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.tw-password-wrapper input {
|
||||
width: 100%;
|
||||
}
|
||||
|
37
boot/boot.js
37
boot/boot.js
@ -448,11 +448,13 @@ Adds a new password prompt. Options are:
|
||||
submitText: text to use for submit button (defaults to "Login")
|
||||
serviceName: text of the human readable service name
|
||||
noUserName: set true to disable username prompt
|
||||
canCancel: set true to enable a cancel button (callback called with null)
|
||||
callback: function to be called on submission with parameter of object {username:,password:}. Callback must return `true` to remove the password prompt
|
||||
*/
|
||||
$tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
// Create and add the prompt to the DOM
|
||||
var submitText = options.submitText || "Login",
|
||||
var self = this,
|
||||
submitText = options.submitText || "Login",
|
||||
dm = $tw.utils.domMaker,
|
||||
children = [dm("h1",{text: options.serviceName})];
|
||||
if(!options.noUserName) {
|
||||
@ -465,6 +467,19 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
attributes: {type: "password", name: "password", placeholder: "Password"},
|
||||
"class": "input-small"
|
||||
}));
|
||||
if(options.canCancel) {
|
||||
children.push(dm("button",{
|
||||
text: "Cancel",
|
||||
"class": "btn",
|
||||
eventListeners: [{
|
||||
name: "click",
|
||||
handlerFunction: function(event) {
|
||||
self.removePrompt(promptInfo);
|
||||
options.callback(null);
|
||||
}
|
||||
}]
|
||||
}));
|
||||
}
|
||||
children.push(dm("button",{
|
||||
attributes: {type: "submit"},
|
||||
text: submitText,
|
||||
@ -492,12 +507,7 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
// Call the callback
|
||||
if(options.callback(data)) {
|
||||
// Remove the prompt if the callback returned true
|
||||
var i = self.passwordPrompts.indexOf(promptInfo);
|
||||
if(i !== -1) {
|
||||
self.passwordPrompts.splice(i,1);
|
||||
promptInfo.form.parentNode.removeChild(promptInfo.form);
|
||||
self.setWrapperDisplay();
|
||||
}
|
||||
self.removePrompt(promptInfo);
|
||||
} else {
|
||||
// Clear the password if the callback returned false
|
||||
$tw.utils.each(form.elements,function(element) {
|
||||
@ -520,6 +530,15 @@ $tw.utils.PasswordPrompt.prototype.createPrompt = function(options) {
|
||||
this.setWrapperDisplay();
|
||||
};
|
||||
|
||||
$tw.utils.PasswordPrompt.prototype.removePrompt = function(promptInfo) {
|
||||
var i = this.passwordPrompts.indexOf(promptInfo);
|
||||
if(i !== -1) {
|
||||
this.passwordPrompts.splice(i,1);
|
||||
promptInfo.form.parentNode.removeChild(promptInfo.form);
|
||||
this.setWrapperDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
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
|
||||
@ -530,7 +549,9 @@ $tw.utils.Crypto = function() {
|
||||
callSjcl = function(method,inputText) {
|
||||
var outputText;
|
||||
try {
|
||||
outputText = sjcl[method](password,inputText);
|
||||
if(password) {
|
||||
outputText = sjcl[method](password,inputText);
|
||||
}
|
||||
} catch(ex) {
|
||||
console.log("Crypto error:" + ex);
|
||||
outputText = null;
|
||||
|
@ -1071,17 +1071,70 @@ exports.readFile = function(file,callback) {
|
||||
// Onload
|
||||
reader.onload = function(event) {
|
||||
// Deserialise the file contents
|
||||
var tiddlerFields = {title: file.name || "Untitled", type: type};
|
||||
var text = event.target.result,
|
||||
tiddlerFields = {title: file.name || "Untitled", type: type};
|
||||
// Are we binary?
|
||||
if(isBinary) {
|
||||
// The base64 section starts after the first comma in the data URI
|
||||
var commaPos = event.target.result.indexOf(",");
|
||||
var commaPos = text.indexOf(",");
|
||||
if(commaPos !== -1) {
|
||||
tiddlerFields.text = event.target.result.substr(commaPos+1);
|
||||
tiddlerFields.text = text.substr(commaPos+1);
|
||||
callback([tiddlerFields]);
|
||||
}
|
||||
} else {
|
||||
callback(self.deserializeTiddlers(type,event.target.result,tiddlerFields));
|
||||
// Check whether this is an encrypted TiddlyWiki file
|
||||
var encryptedStoreAreaStartMarker = "<pre id=\"encryptedStoreArea\" type=\"text/plain\" style=\"display:none;\">",
|
||||
encryptedStoreAreaStart = text.indexOf(encryptedStoreAreaStartMarker),
|
||||
encryptedStoreAreaEnd = encryptedStoreAreaStart !== -1 ? text.indexOf("</pre>",encryptedStoreAreaStart) : -1;
|
||||
if(encryptedStoreAreaStart !== -1 && encryptedStoreAreaEnd !== -1) {
|
||||
var encryptedJson = $tw.utils.htmlDecode(text.substring(encryptedStoreAreaStart + encryptedStoreAreaStartMarker.length,encryptedStoreAreaEnd-1)),
|
||||
attemptDecryption = function() {
|
||||
var decryptedText = $tw.crypto.decrypt(encryptedJson);
|
||||
if(decryptedText) {
|
||||
var json = JSON.parse(decryptedText),
|
||||
tiddlers = [];
|
||||
for(var title in json) {
|
||||
tiddlers.push(json[title]);
|
||||
}
|
||||
return tiddlers;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
// Try to decrypt with the current password
|
||||
var tiddlers = attemptDecryption();
|
||||
if(tiddlers) {
|
||||
callback(tiddlers);
|
||||
} else {
|
||||
// Prompt for a new password and keep trying
|
||||
$tw.passwordPrompt.createPrompt({
|
||||
serviceName: "Enter a password to decrypt the imported TiddlyWiki",
|
||||
noUserName: true,
|
||||
canCancel: true,
|
||||
submitText: "Decrypt",
|
||||
callback: function(data) {
|
||||
// Exit if the user cancelled
|
||||
if(!data) {
|
||||
return false;
|
||||
}
|
||||
// Attempt to decrypt the tiddlers
|
||||
$tw.crypto.setPassword(data.password);
|
||||
var tiddlers = attemptDecryption();
|
||||
if(tiddlers) {
|
||||
callback(tiddlers);
|
||||
// Exit and remove the password prompt
|
||||
return true;
|
||||
} else {
|
||||
// We didn't decrypt everything, so continue to prompt for password
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Try to deserialise any tiddlers in the file
|
||||
callback(self.deserializeTiddlers(type,text,tiddlerFields));
|
||||
}
|
||||
}
|
||||
};
|
||||
// Kick off the read
|
||||
|
@ -16,6 +16,7 @@ type: text/vnd.tiddlywiki
|
||||
|
||||
!! Improvements
|
||||
|
||||
* Added support for importing encrypted TiddlyWiki documents
|
||||
* Added the [[highlight.js|http://highlightjs.org/]] syntax highlighting plugin: http://tiddlywiki.com/highlightdemo.html (thanks to João Bolila, @jbolila on GitHub)
|
||||
* Added the first export option to the ''Tools'' tab of the [[control panel|$:/ControlPanel]]
|
||||
* [[Added|https://github.com/Jermolene/TiddlyWiki5/commit/ffcc215e8f8896be96093579abc5bcfb76335e66]] an ellipsis for [[advanced search|$:/AdvancedSearch]] next to the search box in the sidebar
|
||||
|
Loading…
Reference in New Issue
Block a user