diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js index 99c066f60..df3d673d0 100644 --- a/public/javascripts/context_menu.js +++ b/public/javascripts/context_menu.js @@ -60,10 +60,10 @@ const contextMenuSetup = { noteEditor.createNote(node, node.key, 'into'); } else if (ui.cmd === "encryptSubTree") { - encryptSubTree(node.key); + encryption.encryptSubTree(node.key); } else if (ui.cmd === "decryptSubTree") { - decryptSubTree(node.key); + encryption.decryptSubTree(node.key); } else if (ui.cmd === "cut") { cut(node); diff --git a/public/javascripts/dialogs/note_history.js b/public/javascripts/dialogs/note_history.js index 69d02b858..b5db2fd7d 100644 --- a/public/javascripts/dialogs/note_history.js +++ b/public/javascripts/dialogs/note_history.js @@ -57,8 +57,8 @@ const noteHistory = (function() { let noteText = historyItem.note_text; if (historyItem.encryption > 0) { - noteTitle = decryptString(noteTitle); - noteText = decryptString(noteText); + noteTitle = encryption.decryptString(noteTitle); + noteText = encryption.decryptString(noteText); } titleEl.html(noteTitle); diff --git a/public/javascripts/dialogs/settings.js b/public/javascripts/dialogs/settings.js index ad3cb64a6..1c2160e36 100644 --- a/public/javascripts/dialogs/settings.js +++ b/public/javascripts/dialogs/settings.js @@ -86,19 +86,17 @@ settings.addModule((function() { success: result => { if (result.success) { // 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."); - - $("#settings-dialog").dialog('close'); + message("Password has been changed."); } else { - alert(result.message); + message(result.message); } }, - error: () => alert("Error occurred during changing password.") + error: () => error("Error occurred during changing password.") }); return false; @@ -122,7 +120,7 @@ settings.addModule((function() { const encryptionTimeout = encryptionTimeoutEl.val(); settings.saveSettings(settingName, encryptionTimeout).then(() => { - glob.encryptionSessionTimeout = encryptionTimeout; + encryption.setEncryptionSessionTimeout(encryptionTimeout); }); return false; diff --git a/public/javascripts/encryption.js b/public/javascripts/encryption.js index b4c9567c0..013cf3a52 100644 --- a/public/javascripts/encryption.js +++ b/public/javascripts/encryption.js @@ -1,417 +1,455 @@ -glob.encryptionDeferred = null; +const encryption = (function() { + const dialogEl = $("#encryption-password-dialog"); + const encryptionPasswordFormEl = $("#encryption-password-form"); + const encryptionPasswordEl = $("#encryption-password"); -function handleEncryption(requireEncryption, modal) { - const dfd = $.Deferred(); + let encryptionDeferred = null; + let dataKey = null; + let lastEncryptionOperationDate = null; + let encryptionSalt = null; + let encryptedDataKey = null; + let encryptionSessionTimeout = null; - if (requireEncryption && glob.dataKey === null) { - glob.encryptionDeferred = dfd; + function setEncryptionSalt(encSalt) { + encryptionSalt = encSalt; + } - $("#encryption-password-dialog").dialog({ - modal: modal, - width: 400, - open: () => { - if (!modal) { - // dialog steals focus for itself, which is not what we want for non-modal (viewing) - getNodeByKey(noteEditor.getCurrentNoteId()).setFocus(); + function setEncryptedDataKey(encDataKey) { + encryptedDataKey = encDataKey; + } + + function setEncryptionSessionTimeout(encSessTimeout) { + encryptionSessionTimeout = encSessTimeout; + } + + function ensureEncryptionIsAvailable(requireEncryption, modal) { + const dfd = $.Deferred(); + + if (requireEncryption && dataKey === null) { + encryptionDeferred = dfd; + + dialogEl.dialog({ + modal: modal, + width: 400, + open: () => { + if (!modal) { + // dialog steals focus for itself, which is not what we want for non-modal (viewing) + getNodeByKey(noteEditor.getCurrentNoteId()).setFocus(); + } } + }); + } + else { + dfd.resolve(); + } + + return dfd.promise(); + } + + function getDataKey(password) { + return computeScrypt(password, encryptionSalt, (key, resolve, reject) => { + const dataKeyAes = getDataKeyAes(key); + + const decryptedDataKey = decrypt(dataKeyAes, encryptedDataKey); + + if (decryptedDataKey === false) { + reject("Wrong password."); } + + resolve(decryptedDataKey); }); } - else { - dfd.resolve(); - } - return dfd.promise(); -} + function computeScrypt(password, salt, callback) { + const normalizedPassword = password.normalize('NFKC'); + const passwordBuffer = new buffer.SlowBuffer(normalizedPassword); + const saltBuffer = new buffer.SlowBuffer(salt); -glob.dataKey = null; -glob.lastEncryptionOperationDate = null; + // this settings take ~500ms on my laptop + const N = 16384, r = 8, p = 1; + // 32 byte key - AES 256 + const dkLen = 32; -function getDataKey(password) { - return computeScrypt(password, glob.encryptionSalt, (key, resolve, reject) => { - const dataKeyAes = getDataKeyAes(key); + const startedDate = new Date(); - const decryptedDataKey = decrypt(dataKeyAes, glob.encryptedDataKey); + return new Promise((resolve, reject) => { + scrypt(passwordBuffer, saltBuffer, N, r, p, dkLen, (error, progress, key) => { + if (error) { + console.log("Error: " + error); - if (decryptedDataKey === false) { - reject("Wrong password."); - } + reject(); + } + else if (key) { + console.log("Computation took " + (new Date().getTime() - startedDate.getTime()) + "ms"); - resolve(decryptedDataKey); - }); -} - -function computeScrypt(password, salt, callback) { - const normalizedPassword = password.normalize('NFKC'); - const passwordBuffer = new buffer.SlowBuffer(normalizedPassword); - const saltBuffer = new buffer.SlowBuffer(salt); - - // this settings take ~500ms on my laptop - const N = 16384, r = 8, p = 1; - // 32 byte key - AES 256 - const dkLen = 32; - - const startedDate = new Date(); - - return new Promise((resolve, reject) => { - scrypt(passwordBuffer, saltBuffer, N, r, p, dkLen, (error, progress, key) => { - if (error) { - console.log("Error: " + error); - - reject(); - } - else if (key) { - console.log("Computation took " + (new Date().getTime() - startedDate.getTime()) + "ms"); - - callback(key, resolve, reject); - } - else { - // update UI with progress complete - } + callback(key, resolve, reject); + } + else { + // update UI with progress complete + } + }); }); - }); -} - -function decryptTreeItems() { - if (!isEncryptionAvailable()) { - return; } - for (const noteId of glob.allNoteIds) { - const note = getNodeByKey(noteId); - - if (note.data.encryption > 0) { - const title = decryptString(note.data.note_title); - - note.setTitle(title); + function decryptTreeItems() { + if (!isEncryptionAvailable()) { + return; } - } -} - -$("#encryption-password-form").submit(() => { - const password = $("#encryption-password").val(); - $("#encryption-password").val(""); - - getDataKey(password).then(key => { - $("#encryption-password-dialog").dialog("close"); - - glob.dataKey = key; - - decryptTreeItems(); - - if (glob.encryptionDeferred !== null) { - glob.encryptionDeferred.resolve(); - - glob.encryptionDeferred = null; - } - }) - .catch(reason => { - console.log(reason); - - error(reason); - }); - - return false; -}); - -function resetEncryptionSession() { - glob.dataKey = null; - - if (noteEditor.getCurrentNote().detail.encryption > 0) { - noteEditor.loadNoteToEditor(noteEditor.getCurrentNoteId()); for (const noteId of glob.allNoteIds) { const note = getNodeByKey(noteId); if (note.data.encryption > 0) { - note.setTitle("[encrypted]"); + const title = decryptString(note.data.note_title); + + note.setTitle(title); } } } -} -setInterval(() => { - if (glob.lastEncryptionOperationDate !== null && new Date().getTime() - glob.lastEncryptionOperationDate.getTime() > glob.encryptionSessionTimeout * 1000) { - resetEncryptionSession(); + encryptionPasswordFormEl.submit(() => { + const password = encryptionPasswordEl.val(); + encryptionPasswordEl.val(""); + + getDataKey(password).then(key => { + dialogEl.dialog("close"); + + dataKey = key; + + decryptTreeItems(); + + if (encryptionDeferred !== null) { + encryptionDeferred.resolve(); + + encryptionDeferred = null; + } + }) + .catch(reason => { + console.log(reason); + + error(reason); + }); + + return false; + }); + + function resetEncryptionSession() { + dataKey = null; + + if (noteEditor.getCurrentNote().detail.encryption > 0) { + noteEditor.loadNoteToEditor(noteEditor.getCurrentNoteId()); + + for (const noteId of glob.allNoteIds) { + const note = getNodeByKey(noteId); + + if (note.data.encryption > 0) { + note.setTitle("[encrypted]"); + } + } + } } -}, 5000); -function isEncryptionAvailable() { - return glob.dataKey !== null; -} + setInterval(() => { + if (lastEncryptionOperationDate !== null && new Date().getTime() - lastEncryptionOperationDate.getTime() > encryptionSessionTimeout * 1000) { + resetEncryptionSession(); + } + }, 5000); -function getDataAes() { - glob.lastEncryptionOperationDate = new Date(); + function isEncryptionAvailable() { + return dataKey !== null; + } - return new aesjs.ModeOfOperation.ctr(glob.dataKey, new aesjs.Counter(5)); -} + function getDataAes() { + lastEncryptionOperationDate = new Date(); -function getDataKeyAes(key) { - return new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); -} + return new aesjs.ModeOfOperation.ctr(dataKey, new aesjs.Counter(5)); + } + + function getDataKeyAes(key) { + return new aesjs.ModeOfOperation.ctr(key, new aesjs.Counter(5)); + } + + function encryptNoteIfNecessary(note) { + if (note.detail.encryption === 0) { + return note; + } + else { + return encryptNote(note); + } + } + + function encryptString(str) { + return encrypt(getDataAes(), str); + } + + function encrypt(aes, str) { + const payload = aesjs.utils.utf8.toBytes(str); + const digest = sha256Array(payload).slice(0, 4); + + const digestWithPayload = concat(digest, payload); + + const encryptedBytes = aes.encrypt(digestWithPayload); + + return uint8ToBase64(encryptedBytes); + } + + function decryptString(encryptedBase64) { + const decryptedBytes = decrypt(getDataAes(), encryptedBase64); + + return aesjs.utils.utf8.fromBytes(decryptedBytes); + } + + function decrypt(aes, encryptedBase64) { + const encryptedBytes = base64ToUint8Array(encryptedBase64); + + const decryptedBytes = aes.decrypt(encryptedBytes); + + const digest = decryptedBytes.slice(0, 4); + const payload = decryptedBytes.slice(4); + + const hashArray = sha256Array(payload); + + const computedDigest = hashArray.slice(0, 4); + + if (!arraysIdentical(digest, computedDigest)) { + return false; + } + + return payload; + } + + function concat(a, b) { + const result = []; + + for (let key in a) { + result.push(a[key]); + } + + for (let key in b) { + result.push(b[key]); + } + + return result; + } + + function sha256Array(content) { + const hash = sha256.create(); + hash.update(content); + return hash.array(); + } + + function arraysIdentical(a, b) { + let i = a.length; + if (i !== b.length) return false; + while (i--) { + if (a[i] !== b[i]) return false; + } + return true; + } + + function encryptNote(note) { + note.detail.note_title = encryptString(note.detail.note_title); + note.detail.note_text = encryptString(note.detail.note_text); + + note.detail.encryption = 1; -function encryptNoteIfNecessary(note) { - if (note.detail.encryption === 0) { return note; } - else { - return encryptNote(note); - } -} -function encryptString(str) { - return encrypt(getDataAes(), str); -} + async function encryptNoteAndSendToServer() { + await ensureEncryptionIsAvailable(true, true); -function encrypt(aes, str) { - const payload = aesjs.utils.utf8.toBytes(str); - const digest = sha256Array(payload).slice(0, 4); + const note = noteEditor.getCurrentNote(); - const digestWithPayload = concat(digest, payload); + noteEditor.updateNoteFromInputs(note); - const encryptedBytes = aes.encrypt(digestWithPayload); + encryptNote(note); - return uint8ToBase64(encryptedBytes); -} + await noteEditor.saveNoteToServer(note); -function decryptString(encryptedBase64) { - const decryptedBytes = decrypt(getDataAes(), encryptedBase64); + await changeEncryptionOnNoteHistory(note.detail.note_id, true); - return aesjs.utils.utf8.fromBytes(decryptedBytes); -} - -function decrypt(aes, encryptedBase64) { - const encryptedBytes = base64ToUint8Array(encryptedBase64); - - const decryptedBytes = aes.decrypt(encryptedBytes); - - const digest = decryptedBytes.slice(0, 4); - const payload = decryptedBytes.slice(4); - - const hashArray = sha256Array(payload); - - const computedDigest = hashArray.slice(0, 4); - - if (!arraysIdentical(digest, computedDigest)) { - return false; + noteEditor.setNoteBackgroundIfEncrypted(note); } - return payload; -} - -function concat(a, b) { - const result = []; - - for (let key in a) { - result.push(a[key]); - } - - for (let key in b) { - result.push(b[key]); - } - - return result; -} - -function sha256Array(content) { - const hash = sha256.create(); - hash.update(content); - return hash.array(); -} - -function arraysIdentical(a, b) { - let i = a.length; - if (i !== b.length) return false; - while (i--) { - if (a[i] !== b[i]) return false; - } - return true; -} - -function encryptNote(note) { - note.detail.note_title = encryptString(note.detail.note_title); - note.detail.note_text = encryptString(note.detail.note_text); - - note.detail.encryption = 1; - - return note; -} - -async function encryptNoteAndSendToServer() { - await handleEncryption(true, true); - - const note = noteEditor.getCurrentNote(); - - noteEditor.updateNoteFromInputs(note); - - encryptNote(note); - - await noteEditor.saveNoteToServer(note); - - await changeEncryptionOnNoteHistory(note.detail.note_id, true); - - noteEditor.setNoteBackgroundIfEncrypted(note); -} - -async function changeEncryptionOnNoteHistory(noteId, encrypt) { - const result = await $.ajax({ - url: baseApiUrl + 'notes-history/' + noteId + "?encryption=" + (encrypt ? 0 : 1), - type: 'GET', - error: () => error("Error getting note history.") - }); - - for (const row of result) { - if (encrypt) { - row.note_title = encryptString(row.note_title); - row.note_text = encryptString(row.note_text); - } - else { - row.note_title = decryptString(row.note_title); - row.note_text = decryptString(row.note_text); - } - - row.encryption = encrypt ? 1 : 0; - - await $.ajax({ - url: baseApiUrl + 'notes-history', - type: 'PUT', - contentType: 'application/json', - data: JSON.stringify(row), - error: () => error("Error de/encrypting note history.") + async function changeEncryptionOnNoteHistory(noteId, encrypt) { + const result = await $.ajax({ + url: baseApiUrl + 'notes-history/' + noteId + "?encryption=" + (encrypt ? 0 : 1), + type: 'GET', + error: () => error("Error getting note history.") }); - console.log('Note history ' + row.note_history_id + ' de/encrypted'); - } -} - -async function decryptNoteAndSendToServer() { - await handleEncryption(true, true); - - const note = noteEditor.getCurrentNote(); - - noteEditor.updateNoteFromInputs(note); - - note.detail.encryption = 0; - - await noteEditor.saveNoteToServer(note); - - await changeEncryptionOnNoteHistory(note.detail.note_id, false); - - noteEditor.setNoteBackgroundIfEncrypted(note); -} - -function decryptNoteIfNecessary(note) { - if (note.detail.encryption > 0) { - decryptNote(note); - } -} - -function decryptNote(note) { - note.detail.note_title = decryptString(note.detail.note_title); - note.detail.note_text = decryptString(note.detail.note_text); -} - -async function encryptSubTree(noteId) { - await handleEncryption(true, true); - - updateSubTreeRecursively(noteId, note => { - if (note.detail.encryption === null || note.detail.encryption === 0) { - encryptNote(note); - - note.detail.encryption = 1; - - return true; - } - else { - return false; - } - }, - note => { - if (note.detail.note_id === noteEditor.getCurrentNoteId()) { - noteEditor.loadNoteToEditor(note.detail.note_id); + for (const row of result) { + if (encrypt) { + row.note_title = encryptString(row.note_title); + row.note_text = encryptString(row.note_text); } else { - noteEditor.setTreeBasedOnEncryption(note); - } - }); - - message("Encryption finished."); -} - -async function decryptSubTree(noteId) { - await handleEncryption(true, true); - - updateSubTreeRecursively(noteId, note => { - if (note.detail.encryption === 1) { - decryptNote(note); - - note.detail.encryption = 0; - - return true; - } - else { - return false; - } - }, - note => { - if (note.detail.note_id === noteEditor.getCurrentNoteId()) { - noteEditor.loadNoteToEditor(note.detail.note_id); - } - else { - noteEditor.setTreeBasedOnEncryption(note); - } - }); - - message("Decryption finished."); -} - -function updateSubTreeRecursively(noteId, updateCallback, successCallback) { - updateNoteSynchronously(noteId, updateCallback, successCallback); - - const node = getNodeByKey(noteId); - if (!node || !node.getChildren()) { - return; - } - - for (const child of node.getChildren()) { - updateSubTreeRecursively(child.key, updateCallback, successCallback); - } -} - -function updateNoteSynchronously(noteId, updateCallback, successCallback) { - $.ajax({ - url: baseApiUrl + 'notes/' + noteId, - type: 'GET', - async: false, - success: note => { - const needSave = updateCallback(note); - - if (!needSave) { - return; + row.note_title = decryptString(row.note_title); + row.note_text = decryptString(row.note_text); } - for (const link of note.links) { - delete link.type; - } + row.encryption = encrypt ? 1 : 0; - $.ajax({ - url: baseApiUrl + 'notes/' + noteId, + await $.ajax({ + url: baseApiUrl + 'notes-history', type: 'PUT', - data: JSON.stringify(note), - contentType: "application/json", - async: false, - success: () => { - if (successCallback) { - successCallback(note); - } - }, - error: () => { - console.log("Updating " + noteId + " failed."); + contentType: 'application/json', + data: JSON.stringify(row), + error: () => error("Error de/encrypting note history.") + }); + + console.log('Note history ' + row.note_history_id + ' de/encrypted'); + } + } + + async function decryptNoteAndSendToServer() { + await ensureEncryptionIsAvailable(true, true); + + const note = noteEditor.getCurrentNote(); + + noteEditor.updateNoteFromInputs(note); + + note.detail.encryption = 0; + + await noteEditor.saveNoteToServer(note); + + await changeEncryptionOnNoteHistory(note.detail.note_id, false); + + noteEditor.setNoteBackgroundIfEncrypted(note); + } + + function decryptNoteIfNecessary(note) { + if (note.detail.encryption > 0) { + decryptNote(note); + } + } + + function decryptNote(note) { + note.detail.note_title = decryptString(note.detail.note_title); + note.detail.note_text = decryptString(note.detail.note_text); + } + + async function encryptSubTree(noteId) { + await ensureEncryptionIsAvailable(true, true); + + updateSubTreeRecursively(noteId, note => { + if (note.detail.encryption === null || note.detail.encryption === 0) { + encryptNote(note); + + note.detail.encryption = 1; + + return true; + } + else { + return false; + } + }, + note => { + if (note.detail.note_id === noteEditor.getCurrentNoteId()) { + noteEditor.loadNoteToEditor(note.detail.note_id); + } + else { + noteEditor.setTreeBasedOnEncryption(note); } }); - }, - error: () => { - console.log("Reading " + noteId + " failed."); + + message("Encryption finished."); + } + + async function decryptSubTree(noteId) { + await ensureEncryptionIsAvailable(true, true); + + updateSubTreeRecursively(noteId, note => { + if (note.detail.encryption === 1) { + decryptNote(note); + + note.detail.encryption = 0; + + return true; + } + else { + return false; + } + }, + note => { + if (note.detail.note_id === noteEditor.getCurrentNoteId()) { + noteEditor.loadNoteToEditor(note.detail.note_id); + } + else { + noteEditor.setTreeBasedOnEncryption(note); + } + }); + + message("Decryption finished."); + } + + function updateSubTreeRecursively(noteId, updateCallback, successCallback) { + updateNoteSynchronously(noteId, updateCallback, successCallback); + + const node = getNodeByKey(noteId); + if (!node || !node.getChildren()) { + return; } - }); -} \ No newline at end of file + + for (const child of node.getChildren()) { + updateSubTreeRecursively(child.key, updateCallback, successCallback); + } + } + + function updateNoteSynchronously(noteId, updateCallback, successCallback) { + $.ajax({ + url: baseApiUrl + 'notes/' + noteId, + type: 'GET', + async: false, + success: note => { + const needSave = updateCallback(note); + + if (!needSave) { + return; + } + + for (const link of note.links) { + delete link.type; + } + + $.ajax({ + url: baseApiUrl + 'notes/' + noteId, + type: 'PUT', + data: JSON.stringify(note), + contentType: "application/json", + async: false, + success: () => { + if (successCallback) { + successCallback(note); + } + }, + error: () => { + console.log("Updating " + noteId + " failed."); + } + }); + }, + error: () => { + console.log("Reading " + noteId + " failed."); + } + }); + } + + return { + setEncryptionSalt, + setEncryptedDataKey, + setEncryptionSessionTimeout, + ensureEncryptionIsAvailable, + decryptTreeItems, + resetEncryptionSession, + isEncryptionAvailable, + encryptNoteIfNecessary, + encryptString, + decryptString, + encryptNoteAndSendToServer, + decryptNoteAndSendToServer, + decryptNoteIfNecessary, + encryptSubTree, + decryptSubTree + }; +})(); \ No newline at end of file diff --git a/public/javascripts/note_editor.js b/public/javascripts/note_editor.js index ed55779d0..b1231fe6d 100644 --- a/public/javascripts/note_editor.js +++ b/public/javascripts/note_editor.js @@ -1,7 +1,6 @@ const noteEditor = (function() { const noteTitleEl = $("#note-title"); const noteDetailEl = $('#note-detail'); - const noteEditableEl = $(".note-editable"); const encryptButton = $("#encrypt-button"); const decryptButton = $("#decrypt-button"); const noteDetailWrapperEl = $("#note-detail-wrapper"); @@ -44,7 +43,7 @@ const noteEditor = (function() { updateNoteFromInputs(note); - encryptNoteIfNecessary(note); + encryption.encryptNoteIfNecessary(note); await saveNoteToServer(note); } @@ -112,12 +111,12 @@ const noteEditor = (function() { async function createNote(node, parentKey, target, encryption) { // 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 - if (!encryption || !isEncryptionAvailable()) { + if (!encryption || !encryption.isEncryptionAvailable()) { encryption = 0; } const newNoteName = "new note"; - const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryptString(newNoteName) : newNoteName; + const newNoteNameEncryptedIfNecessary = encryption > 0 ? encryption.encryptString(newNoteName) : newNoteName; const result = await $.ajax({ url: baseApiUrl + 'notes/' + parentKey + '/children' , @@ -163,12 +162,12 @@ const noteEditor = (function() { function setNoteBackgroundIfEncrypted(note) { if (note.detail.encryption > 0) { - noteEditableEl.addClass("encrypted"); + $(".note-editable").addClass("encrypted"); encryptButton.hide(); decryptButton.show(); } else { - noteEditableEl.removeClass("encrypted"); + $(".note-editable").removeClass("encrypted"); encryptButton.show(); decryptButton.hide(); } @@ -187,7 +186,7 @@ const noteEditor = (function() { noteTitleEl.focus().select(); } - await handleEncryption(note.detail.encryption > 0, false); + await encryption.ensureEncryptionIsAvailable(note.detail.encryption > 0, false); noteDetailWrapperEl.show(); @@ -199,7 +198,7 @@ const noteEditor = (function() { encryptionPasswordEl.val(''); - decryptNoteIfNecessary(note); + encryption.decryptNoteIfNecessary(note); noteTitleEl.val(note.detail.note_title); @@ -222,11 +221,11 @@ const noteEditor = (function() { async function loadNote(noteId) { const note = await $.get(baseApiUrl + 'notes/' + noteId); - if (note.detail.encryption > 0 && !isEncryptionAvailable()) { + if (note.detail.encryption > 0 && !encryption.isEncryptionAvailable()) { return; } - decryptNoteIfNecessary(note); + encryption.decryptNoteIfNecessary(note); return note; } @@ -245,7 +244,7 @@ const noteEditor = (function() { }); // so that tab jumps from note title (which has tabindex 1) - noteEditableEl.attr("tabindex", 2); + $(".note-editable").attr("tabindex", 2); }); setInterval(saveNoteIfChanged, 5000); diff --git a/public/javascripts/status.js b/public/javascripts/status.js index 31eefb179..2c3a0697d 100644 --- a/public/javascripts/status.js +++ b/public/javascripts/status.js @@ -29,7 +29,7 @@ async function checkStatus() { // this will also reload the note content await glob.tree.fancytree('getTree').reload(treeResp.notes); - decryptTreeItems(); + encryption.decryptTreeItems(); } $("#changesToPushCount").html(resp.changesToPushCount); diff --git a/public/javascripts/tree.js b/public/javascripts/tree.js index 59c240378..cc9dbe9ce 100644 --- a/public/javascripts/tree.js +++ b/public/javascripts/tree.js @@ -81,9 +81,6 @@ function setExpandedToServer(note_id, is_expanded) { }); } -glob.encryptionSalt; -glob.encryptionSessionTimeout; -glob.encryptedDataKey; glob.treeLoadTime; function initFancyTree(notes, startNoteId) { @@ -181,9 +178,9 @@ function loadTree() { return $.get(baseApiUrl + 'tree').then(resp => { const notes = resp.notes; let startNoteId = resp.start_note_id; - glob.encryptionSalt = resp.password_derived_key_salt; - glob.encryptionSessionTimeout = resp.encryption_session_timeout; - glob.encryptedDataKey = resp.encrypted_data_key; + encryption.setEncryptionSalt(resp.password_derived_key_salt); + encryption.setEncryptionSessionTimeout(resp.encryption_session_timeout); + encryption.setEncryptedDataKey(resp.encrypted_data_key); glob.treeLoadTime = resp.tree_load_time; // add browser ID header to all AJAX requests diff --git a/public/javascripts/tree_utils.js b/public/javascripts/tree_utils.js index 246398481..95da0f9a2 100644 --- a/public/javascripts/tree_utils.js +++ b/public/javascripts/tree_utils.js @@ -40,7 +40,7 @@ function getFullName(noteId) { const path = []; while (note) { - if (note.data.encryption > 0 && !isEncryptionAvailable()) { + if (note.data.encryption > 0 && !encryption.isEncryptionAvailable()) { path.push("[encrypted]"); } else { diff --git a/views/index.ejs b/views/index.ejs index 9b8629a0f..68333dad9 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -64,7 +64,7 @@