mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	encryption converted to module
This commit is contained in:
		| @@ -60,10 +60,10 @@ const contextMenuSetup = { | |||||||
|             noteEditor.createNote(node, node.key, 'into'); |             noteEditor.createNote(node, node.key, 'into'); | ||||||
|         } |         } | ||||||
|         else if (ui.cmd === "encryptSubTree") { |         else if (ui.cmd === "encryptSubTree") { | ||||||
|             encryptSubTree(node.key); |             encryption.encryptSubTree(node.key); | ||||||
|         } |         } | ||||||
|         else if (ui.cmd === "decryptSubTree") { |         else if (ui.cmd === "decryptSubTree") { | ||||||
|             decryptSubTree(node.key); |             encryption.decryptSubTree(node.key); | ||||||
|         } |         } | ||||||
|         else if (ui.cmd === "cut") { |         else if (ui.cmd === "cut") { | ||||||
|             cut(node); |             cut(node); | ||||||
|   | |||||||
| @@ -57,8 +57,8 @@ const noteHistory = (function() { | |||||||
|         let noteText = historyItem.note_text; |         let noteText = historyItem.note_text; | ||||||
|  |  | ||||||
|         if (historyItem.encryption > 0) { |         if (historyItem.encryption > 0) { | ||||||
|             noteTitle = decryptString(noteTitle); |             noteTitle = encryption.decryptString(noteTitle); | ||||||
|             noteText = decryptString(noteText); |             noteText = encryption.decryptString(noteText); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         titleEl.html(noteTitle); |         titleEl.html(noteTitle); | ||||||
|   | |||||||
| @@ -86,19 +86,17 @@ settings.addModule((function() { | |||||||
|             success: result => { |             success: result => { | ||||||
|                 if (result.success) { |                 if (result.success) { | ||||||
|                     // encryption password changed so current encryption session is invalid and needs to be cleared |                     // encryption password changed so current encryption session is invalid and needs to be cleared | ||||||
|                     resetEncryptionSession(); |                     encryption.resetEncryptionSession(); | ||||||
|  |  | ||||||
|                     glob.encryptedDataKey = result.new_encrypted_data_key; |                     encryption.setEncryptedDataKey(result.new_encrypted_data_key); | ||||||
|  |  | ||||||
|                     alert("Password has been changed."); |                     message("Password has been changed."); | ||||||
|  |  | ||||||
|                     $("#settings-dialog").dialog('close'); |  | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     alert(result.message); |                     message(result.message); | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             error: () => alert("Error occurred during changing password.") |             error: () => error("Error occurred during changing password.") | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
| @@ -122,7 +120,7 @@ settings.addModule((function() { | |||||||
|         const encryptionTimeout = encryptionTimeoutEl.val(); |         const encryptionTimeout = encryptionTimeoutEl.val(); | ||||||
|  |  | ||||||
|         settings.saveSettings(settingName, encryptionTimeout).then(() => { |         settings.saveSettings(settingName, encryptionTimeout).then(() => { | ||||||
|             glob.encryptionSessionTimeout = encryptionTimeout; |             encryption.setEncryptionSessionTimeout(encryptionTimeout); | ||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         return false; |         return false; | ||||||
|   | |||||||
| @@ -1,12 +1,34 @@ | |||||||
| glob.encryptionDeferred = null; | const encryption = (function() { | ||||||
|  |     const dialogEl = $("#encryption-password-dialog"); | ||||||
|  |     const encryptionPasswordFormEl = $("#encryption-password-form"); | ||||||
|  |     const encryptionPasswordEl = $("#encryption-password"); | ||||||
|  |  | ||||||
| function handleEncryption(requireEncryption, modal) { |     let encryptionDeferred = null; | ||||||
|  |     let dataKey = null; | ||||||
|  |     let lastEncryptionOperationDate = null; | ||||||
|  |     let encryptionSalt = null; | ||||||
|  |     let encryptedDataKey = null; | ||||||
|  |     let encryptionSessionTimeout = null; | ||||||
|  |  | ||||||
|  |     function setEncryptionSalt(encSalt) { | ||||||
|  |         encryptionSalt = encSalt; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setEncryptedDataKey(encDataKey) { | ||||||
|  |         encryptedDataKey = encDataKey; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function setEncryptionSessionTimeout(encSessTimeout) { | ||||||
|  |         encryptionSessionTimeout = encSessTimeout; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function ensureEncryptionIsAvailable(requireEncryption, modal) { | ||||||
|         const dfd = $.Deferred(); |         const dfd = $.Deferred(); | ||||||
|  |  | ||||||
|     if (requireEncryption && glob.dataKey === null) { |         if (requireEncryption && dataKey === null) { | ||||||
|         glob.encryptionDeferred = dfd; |             encryptionDeferred = dfd; | ||||||
|  |  | ||||||
|         $("#encryption-password-dialog").dialog({ |             dialogEl.dialog({ | ||||||
|                 modal: modal, |                 modal: modal, | ||||||
|                 width: 400, |                 width: 400, | ||||||
|                 open: () => { |                 open: () => { | ||||||
| @@ -24,14 +46,11 @@ function handleEncryption(requireEncryption, modal) { | |||||||
|         return dfd.promise(); |         return dfd.promise(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| glob.dataKey = null; |  | ||||||
| glob.lastEncryptionOperationDate = null; |  | ||||||
|  |  | ||||||
|     function getDataKey(password) { |     function getDataKey(password) { | ||||||
|     return computeScrypt(password, glob.encryptionSalt, (key, resolve, reject) => { |         return computeScrypt(password, encryptionSalt, (key, resolve, reject) => { | ||||||
|             const dataKeyAes = getDataKeyAes(key); |             const dataKeyAes = getDataKeyAes(key); | ||||||
|  |  | ||||||
|         const decryptedDataKey = decrypt(dataKeyAes, glob.encryptedDataKey); |             const decryptedDataKey = decrypt(dataKeyAes, encryptedDataKey); | ||||||
|  |  | ||||||
|             if (decryptedDataKey === false) { |             if (decryptedDataKey === false) { | ||||||
|                 reject("Wrong password."); |                 reject("Wrong password."); | ||||||
| @@ -88,21 +107,21 @@ function decryptTreeItems() { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| $("#encryption-password-form").submit(() => { |     encryptionPasswordFormEl.submit(() => { | ||||||
|     const password = $("#encryption-password").val(); |         const password = encryptionPasswordEl.val(); | ||||||
|     $("#encryption-password").val(""); |         encryptionPasswordEl.val(""); | ||||||
|  |  | ||||||
|         getDataKey(password).then(key => { |         getDataKey(password).then(key => { | ||||||
|         $("#encryption-password-dialog").dialog("close"); |             dialogEl.dialog("close"); | ||||||
|  |  | ||||||
|         glob.dataKey = key; |             dataKey = key; | ||||||
|  |  | ||||||
|             decryptTreeItems(); |             decryptTreeItems(); | ||||||
|  |  | ||||||
|         if (glob.encryptionDeferred !== null) { |             if (encryptionDeferred !== null) { | ||||||
|             glob.encryptionDeferred.resolve(); |                 encryptionDeferred.resolve(); | ||||||
|  |  | ||||||
|             glob.encryptionDeferred = null; |                 encryptionDeferred = null; | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|             .catch(reason => { |             .catch(reason => { | ||||||
| @@ -115,7 +134,7 @@ $("#encryption-password-form").submit(() => { | |||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     function resetEncryptionSession() { |     function resetEncryptionSession() { | ||||||
|     glob.dataKey = null; |         dataKey = null; | ||||||
|  |  | ||||||
|         if (noteEditor.getCurrentNote().detail.encryption > 0) { |         if (noteEditor.getCurrentNote().detail.encryption > 0) { | ||||||
|             noteEditor.loadNoteToEditor(noteEditor.getCurrentNoteId()); |             noteEditor.loadNoteToEditor(noteEditor.getCurrentNoteId()); | ||||||
| @@ -131,19 +150,19 @@ function resetEncryptionSession() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     setInterval(() => { |     setInterval(() => { | ||||||
|     if (glob.lastEncryptionOperationDate !== null && new Date().getTime() - glob.lastEncryptionOperationDate.getTime() > glob.encryptionSessionTimeout * 1000) { |         if (lastEncryptionOperationDate !== null && new Date().getTime() - lastEncryptionOperationDate.getTime() > encryptionSessionTimeout * 1000) { | ||||||
|             resetEncryptionSession(); |             resetEncryptionSession(); | ||||||
|         } |         } | ||||||
|     }, 5000); |     }, 5000); | ||||||
|  |  | ||||||
|     function isEncryptionAvailable() { |     function isEncryptionAvailable() { | ||||||
|     return glob.dataKey !== null; |         return dataKey !== null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function getDataAes() { |     function getDataAes() { | ||||||
|     glob.lastEncryptionOperationDate = new Date(); |         lastEncryptionOperationDate = new Date(); | ||||||
|  |  | ||||||
|     return new aesjs.ModeOfOperation.ctr(glob.dataKey, new aesjs.Counter(5)); |         return new aesjs.ModeOfOperation.ctr(dataKey, new aesjs.Counter(5)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     function getDataKeyAes(key) { |     function getDataKeyAes(key) { | ||||||
| @@ -238,7 +257,7 @@ function encryptNote(note) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function encryptNoteAndSendToServer() { |     async function encryptNoteAndSendToServer() { | ||||||
|     await handleEncryption(true, true); |         await ensureEncryptionIsAvailable(true, true); | ||||||
|  |  | ||||||
|         const note = noteEditor.getCurrentNote(); |         const note = noteEditor.getCurrentNote(); | ||||||
|  |  | ||||||
| @@ -285,7 +304,7 @@ async function changeEncryptionOnNoteHistory(noteId, encrypt) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function decryptNoteAndSendToServer() { |     async function decryptNoteAndSendToServer() { | ||||||
|     await handleEncryption(true, true); |         await ensureEncryptionIsAvailable(true, true); | ||||||
|  |  | ||||||
|         const note = noteEditor.getCurrentNote(); |         const note = noteEditor.getCurrentNote(); | ||||||
|  |  | ||||||
| @@ -312,7 +331,7 @@ function decryptNote(note) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function encryptSubTree(noteId) { |     async function encryptSubTree(noteId) { | ||||||
|     await handleEncryption(true, true); |         await ensureEncryptionIsAvailable(true, true); | ||||||
|  |  | ||||||
|         updateSubTreeRecursively(noteId, note => { |         updateSubTreeRecursively(noteId, note => { | ||||||
|                 if (note.detail.encryption === null || note.detail.encryption === 0) { |                 if (note.detail.encryption === null || note.detail.encryption === 0) { | ||||||
| @@ -339,7 +358,7 @@ async function encryptSubTree(noteId) { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     async function decryptSubTree(noteId) { |     async function decryptSubTree(noteId) { | ||||||
|     await handleEncryption(true, true); |         await ensureEncryptionIsAvailable(true, true); | ||||||
|  |  | ||||||
|         updateSubTreeRecursively(noteId, note => { |         updateSubTreeRecursively(noteId, note => { | ||||||
|                 if (note.detail.encryption === 1) { |                 if (note.detail.encryption === 1) { | ||||||
| @@ -415,3 +434,22 @@ function updateNoteSynchronously(noteId, updateCallback, successCallback) { | |||||||
|             } |             } | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |         setEncryptionSalt, | ||||||
|  |         setEncryptedDataKey, | ||||||
|  |         setEncryptionSessionTimeout, | ||||||
|  |         ensureEncryptionIsAvailable, | ||||||
|  |         decryptTreeItems, | ||||||
|  |         resetEncryptionSession, | ||||||
|  |         isEncryptionAvailable, | ||||||
|  |         encryptNoteIfNecessary, | ||||||
|  |         encryptString, | ||||||
|  |         decryptString, | ||||||
|  |         encryptNoteAndSendToServer, | ||||||
|  |         decryptNoteAndSendToServer, | ||||||
|  |         decryptNoteIfNecessary, | ||||||
|  |         encryptSubTree, | ||||||
|  |         decryptSubTree | ||||||
|  |     }; | ||||||
|  | })(); | ||||||
| @@ -1,7 +1,6 @@ | |||||||
| const noteEditor = (function() { | const noteEditor = (function() { | ||||||
|     const noteTitleEl = $("#note-title"); |     const noteTitleEl = $("#note-title"); | ||||||
|     const noteDetailEl = $('#note-detail'); |     const noteDetailEl = $('#note-detail'); | ||||||
|     const noteEditableEl = $(".note-editable"); |  | ||||||
|     const encryptButton = $("#encrypt-button"); |     const encryptButton = $("#encrypt-button"); | ||||||
|     const decryptButton = $("#decrypt-button"); |     const decryptButton = $("#decrypt-button"); | ||||||
|     const noteDetailWrapperEl = $("#note-detail-wrapper"); |     const noteDetailWrapperEl = $("#note-detail-wrapper"); | ||||||
| @@ -44,7 +43,7 @@ const noteEditor = (function() { | |||||||
|  |  | ||||||
|         updateNoteFromInputs(note); |         updateNoteFromInputs(note); | ||||||
|  |  | ||||||
|         encryptNoteIfNecessary(note); |         encryption.encryptNoteIfNecessary(note); | ||||||
|  |  | ||||||
|         await saveNoteToServer(note); |         await saveNoteToServer(note); | ||||||
|     } |     } | ||||||
| @@ -112,12 +111,12 @@ const noteEditor = (function() { | |||||||
|     async function createNote(node, parentKey, target, encryption) { |     async function createNote(node, parentKey, target, encryption) { | ||||||
|         // if encryption isn't available (user didn't enter password yet), then note is created as unencrypted |         // if encryption isn't available (user didn't enter password yet), then note is created as unencrypted | ||||||
|         // but this is quite weird since user doesn't see where the note is being created so it shouldn't occur often |         // but this is quite weird since user doesn't see where the note is being created so it shouldn't occur often | ||||||
|         if (!encryption || !isEncryptionAvailable()) { |         if (!encryption || !encryption.isEncryptionAvailable()) { | ||||||
|             encryption = 0; |             encryption = 0; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const newNoteName = "new note"; |         const newNoteName = "new note"; | ||||||
|         const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryptString(newNoteName) : newNoteName; |         const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryption.encryptString(newNoteName) : newNoteName; | ||||||
|  |  | ||||||
|         const result = await $.ajax({ |         const result = await $.ajax({ | ||||||
|             url: baseApiUrl + 'notes/' + parentKey + '/children' , |             url: baseApiUrl + 'notes/' + parentKey + '/children' , | ||||||
| @@ -163,12 +162,12 @@ const noteEditor = (function() { | |||||||
|  |  | ||||||
|     function setNoteBackgroundIfEncrypted(note) { |     function setNoteBackgroundIfEncrypted(note) { | ||||||
|         if (note.detail.encryption > 0) { |         if (note.detail.encryption > 0) { | ||||||
|             noteEditableEl.addClass("encrypted"); |             $(".note-editable").addClass("encrypted"); | ||||||
|             encryptButton.hide(); |             encryptButton.hide(); | ||||||
|             decryptButton.show(); |             decryptButton.show(); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             noteEditableEl.removeClass("encrypted"); |             $(".note-editable").removeClass("encrypted"); | ||||||
|             encryptButton.show(); |             encryptButton.show(); | ||||||
|             decryptButton.hide(); |             decryptButton.hide(); | ||||||
|         } |         } | ||||||
| @@ -187,7 +186,7 @@ const noteEditor = (function() { | |||||||
|             noteTitleEl.focus().select(); |             noteTitleEl.focus().select(); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         await handleEncryption(note.detail.encryption > 0, false); |         await encryption.ensureEncryptionIsAvailable(note.detail.encryption > 0, false); | ||||||
|  |  | ||||||
|         noteDetailWrapperEl.show(); |         noteDetailWrapperEl.show(); | ||||||
|  |  | ||||||
| @@ -199,7 +198,7 @@ const noteEditor = (function() { | |||||||
|  |  | ||||||
|         encryptionPasswordEl.val(''); |         encryptionPasswordEl.val(''); | ||||||
|  |  | ||||||
|         decryptNoteIfNecessary(note); |         encryption.decryptNoteIfNecessary(note); | ||||||
|  |  | ||||||
|         noteTitleEl.val(note.detail.note_title); |         noteTitleEl.val(note.detail.note_title); | ||||||
|  |  | ||||||
| @@ -222,11 +221,11 @@ const noteEditor = (function() { | |||||||
|     async function loadNote(noteId) { |     async function loadNote(noteId) { | ||||||
|         const note = await $.get(baseApiUrl + 'notes/' + noteId); |         const note = await $.get(baseApiUrl + 'notes/' + noteId); | ||||||
|  |  | ||||||
|         if (note.detail.encryption > 0 && !isEncryptionAvailable()) { |         if (note.detail.encryption > 0 && !encryption.isEncryptionAvailable()) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         decryptNoteIfNecessary(note); |         encryption.decryptNoteIfNecessary(note); | ||||||
|  |  | ||||||
|         return note; |         return note; | ||||||
|     } |     } | ||||||
| @@ -245,7 +244,7 @@ const noteEditor = (function() { | |||||||
|         }); |         }); | ||||||
|  |  | ||||||
|         // so that tab jumps from note title (which has tabindex 1) |         // so that tab jumps from note title (which has tabindex 1) | ||||||
|         noteEditableEl.attr("tabindex", 2); |         $(".note-editable").attr("tabindex", 2); | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     setInterval(saveNoteIfChanged, 5000); |     setInterval(saveNoteIfChanged, 5000); | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ async function checkStatus() { | |||||||
|         // this will also reload the note content |         // this will also reload the note content | ||||||
|         await glob.tree.fancytree('getTree').reload(treeResp.notes); |         await glob.tree.fancytree('getTree').reload(treeResp.notes); | ||||||
|  |  | ||||||
|         decryptTreeItems(); |         encryption.decryptTreeItems(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $("#changesToPushCount").html(resp.changesToPushCount); |     $("#changesToPushCount").html(resp.changesToPushCount); | ||||||
|   | |||||||
| @@ -81,9 +81,6 @@ function setExpandedToServer(note_id, is_expanded) { | |||||||
|     }); |     }); | ||||||
| } | } | ||||||
|  |  | ||||||
| glob.encryptionSalt; |  | ||||||
| glob.encryptionSessionTimeout; |  | ||||||
| glob.encryptedDataKey; |  | ||||||
| glob.treeLoadTime; | glob.treeLoadTime; | ||||||
|  |  | ||||||
| function initFancyTree(notes, startNoteId) { | function initFancyTree(notes, startNoteId) { | ||||||
| @@ -181,9 +178,9 @@ function loadTree() { | |||||||
|     return $.get(baseApiUrl + 'tree').then(resp => { |     return $.get(baseApiUrl + 'tree').then(resp => { | ||||||
|         const notes = resp.notes; |         const notes = resp.notes; | ||||||
|         let startNoteId = resp.start_note_id; |         let startNoteId = resp.start_note_id; | ||||||
|         glob.encryptionSalt = resp.password_derived_key_salt; |         encryption.setEncryptionSalt(resp.password_derived_key_salt); | ||||||
|         glob.encryptionSessionTimeout = resp.encryption_session_timeout; |         encryption.setEncryptionSessionTimeout(resp.encryption_session_timeout); | ||||||
|         glob.encryptedDataKey = resp.encrypted_data_key; |         encryption.setEncryptedDataKey(resp.encrypted_data_key); | ||||||
|         glob.treeLoadTime = resp.tree_load_time; |         glob.treeLoadTime = resp.tree_load_time; | ||||||
|  |  | ||||||
|         // add browser ID header to all AJAX requests |         // add browser ID header to all AJAX requests | ||||||
|   | |||||||
| @@ -40,7 +40,7 @@ function getFullName(noteId) { | |||||||
|     const path = []; |     const path = []; | ||||||
|  |  | ||||||
|     while (note) { |     while (note) { | ||||||
|         if (note.data.encryption > 0 && !isEncryptionAvailable()) { |         if (note.data.encryption > 0 && !encryption.isEncryptionAvailable()) { | ||||||
|             path.push("[encrypted]"); |             path.push("[encrypted]"); | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|   | |||||||
| @@ -64,7 +64,7 @@ | |||||||
|  |  | ||||||
|       <div class="hide-toggle" style="grid-area: title;"> |       <div class="hide-toggle" style="grid-area: title;"> | ||||||
|         <div style="display: flex; align-items: center;"> |         <div style="display: flex; align-items: center;"> | ||||||
|           <a onclick="encryptNoteAndSendToServer()" |           <a onclick="encryption.encryptNoteAndSendToServer()" | ||||||
|              title="Encrypt the note so that password will be required to view the note" |              title="Encrypt the note so that password will be required to view the note" | ||||||
|              class="icon-action" |              class="icon-action" | ||||||
|              id="encrypt-button" |              id="encrypt-button" | ||||||
| @@ -72,7 +72,7 @@ | |||||||
|             <img src="images/icons/lock.png" alt="Encrypt note"/> |             <img src="images/icons/lock.png" alt="Encrypt note"/> | ||||||
|           </a> |           </a> | ||||||
|  |  | ||||||
|           <a onclick="decryptNoteAndSendToServer()" |           <a onclick="encryption.decryptNoteAndSendToServer()" | ||||||
|              title="Decrypt note permamently so that password will not be required to access this note in the future" |              title="Decrypt note permamently so that password will not be required to access this note in the future" | ||||||
|              class="icon-action" |              class="icon-action" | ||||||
|              id="decrypt-button" |              id="decrypt-button" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user