mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	server side encryption WIP
This commit is contained in:
		| @@ -91,8 +91,6 @@ settings.addModule((function() { | ||||
|  | ||||
|                     // encryption password changed so current encryption session is invalid and needs to be cleared | ||||
|                     encryption.resetEncryptionSession(); | ||||
|  | ||||
|                     encryption.setEncryptedDataKey(result.new_encrypted_data_key); | ||||
|                 } | ||||
|                 else { | ||||
|                     showError(result.message); | ||||
|   | ||||
| @@ -23,10 +23,6 @@ const encryption = (function() { | ||||
|         encryptedDataKey = settings.encrypted_data_key; | ||||
|     }); | ||||
|  | ||||
|     function setEncryptedDataKey(encDataKey) { | ||||
|         encryptedDataKey = encDataKey; | ||||
|     } | ||||
|  | ||||
|     function setEncryptionSessionTimeout(encSessTimeout) { | ||||
|         encryptionSessionTimeout = encSessTimeout; | ||||
|     } | ||||
| @@ -34,7 +30,7 @@ const encryption = (function() { | ||||
|     function ensureEncryptionIsAvailable(requireEncryption, modal) { | ||||
|         const dfd = $.Deferred(); | ||||
|  | ||||
|         if (requireEncryption && dataKey === null) { | ||||
|         if (requireEncryption && !isEncryptionAvailable()) { | ||||
|             // if this is entry point then we need to show the app even before the note is loaded | ||||
|             showAppIfHidden(); | ||||
|  | ||||
| @@ -58,54 +54,6 @@ const encryption = (function() { | ||||
|         return dfd.promise(); | ||||
|     } | ||||
|  | ||||
|     async function getDataKey(password) { | ||||
|         const passwordDerivedKey = await computeScrypt(password, passwordDerivedKeySalt); | ||||
|  | ||||
|         const dataKeyAes = getDataKeyAes(passwordDerivedKey); | ||||
|  | ||||
|         return decrypt(dataKeyAes, encryptedDataKey); | ||||
|     } | ||||
|  | ||||
|     function computeScrypt(password, salt) { | ||||
|         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; | ||||
|  | ||||
|         return new Promise((resolve, reject) => { | ||||
|             scrypt(passwordBuffer, saltBuffer, N, r, p, dkLen, (error, progress, key) => { | ||||
|                 if (error) { | ||||
|                     showError(error); | ||||
|  | ||||
|                     reject(error); | ||||
|                 } | ||||
|                 else if (key) { | ||||
|                     resolve(key); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function decryptTreeItems() { | ||||
|         if (!isEncryptionAvailable()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for (const noteId of glob.allNoteIds) { | ||||
|             const note = treeUtils.getNodeByKey(noteId); | ||||
|  | ||||
|             if (note.data.encryption > 0) { | ||||
|                 const title = decryptString(note.data.note_title); | ||||
|  | ||||
|                 note.setTitle(title); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     async function setupEncryptionSession() { | ||||
|         const password = encryptionPasswordEl.val(); | ||||
|         encryptionPasswordEl.val(""); | ||||
| @@ -122,6 +70,7 @@ const encryption = (function() { | ||||
|  | ||||
|         dialogEl.dialog("close"); | ||||
|  | ||||
|         noteEditor.reload(); | ||||
|         noteTree.reload(); | ||||
|  | ||||
|         if (encryptionDeferred !== null) { | ||||
| @@ -158,7 +107,7 @@ const encryption = (function() { | ||||
|     } | ||||
|  | ||||
|     function isEncryptionAvailable() { | ||||
|         return dataKey !== null; | ||||
|         return protectedSessionId !== null; | ||||
|     } | ||||
|  | ||||
|     function getDataAes() { | ||||
| @@ -167,10 +116,6 @@ const encryption = (function() { | ||||
|         return new aesjs.ModeOfOperation.ctr(dataKey, new aesjs.Counter(5)); | ||||
|     } | ||||
|  | ||||
|     function getDataKeyAes(passwordDerivedKey) { | ||||
|         return new aesjs.ModeOfOperation.ctr(passwordDerivedKey, new aesjs.Counter(5)); | ||||
|     } | ||||
|  | ||||
|     function encryptNoteIfNecessary(note) { | ||||
|         if (note.detail.encryption === 0) { | ||||
|             return note; | ||||
| @@ -307,17 +252,6 @@ const encryption = (function() { | ||||
|         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); | ||||
|  | ||||
| @@ -433,10 +367,8 @@ const encryption = (function() { | ||||
|     }, 5000); | ||||
|  | ||||
|     return { | ||||
|         setEncryptedDataKey, | ||||
|         setEncryptionSessionTimeout, | ||||
|         ensureEncryptionIsAvailable, | ||||
|         decryptTreeItems, | ||||
|         resetEncryptionSession, | ||||
|         isEncryptionAvailable, | ||||
|         encryptNoteIfNecessary, | ||||
| @@ -444,7 +376,6 @@ const encryption = (function() { | ||||
|         decryptString, | ||||
|         encryptNoteAndSendToServer, | ||||
|         decryptNoteAndSendToServer, | ||||
|         decryptNoteIfNecessary, | ||||
|         encryptSubTree, | ||||
|         decryptSubTree, | ||||
|         getProtectedSessionId | ||||
|   | ||||
| @@ -209,8 +209,6 @@ const noteEditor = (function() { | ||||
|  | ||||
|         encryptionPasswordEl.val(''); | ||||
|  | ||||
|         encryption.decryptNoteIfNecessary(currentNote); | ||||
|  | ||||
|         noteTitleEl.val(currentNote.detail.note_title); | ||||
|  | ||||
|         noteChangeDisabled = true; | ||||
| @@ -234,12 +232,6 @@ const noteEditor = (function() { | ||||
|     async function loadNote(noteId) { | ||||
|         const note = await $.get(baseApiUrl + 'notes/' + noteId); | ||||
|  | ||||
|         if (note.detail.encryption > 0 && !encryption.isEncryptionAvailable()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         encryption.decryptNoteIfNecessary(note); | ||||
|  | ||||
|         return note; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -190,8 +190,6 @@ const noteTree = (function() { | ||||
|  | ||||
|         // this will also reload the note content | ||||
|         await treeEl.fancytree('getTree').reload(treeResp.notes); | ||||
|  | ||||
|         encryption.decryptTreeItems(); | ||||
|     } | ||||
|  | ||||
|     function loadTree() { | ||||
|   | ||||
| @@ -7,6 +7,8 @@ const sql = require('../../services/sql'); | ||||
| const options = require('../../services/options'); | ||||
| const utils = require('../../services/utils'); | ||||
| const notes = require('../../services/notes'); | ||||
| const protected_session = require('../../services/protected_session'); | ||||
| const data_encryption = require('../../services/data_encryption'); | ||||
|  | ||||
| router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { | ||||
|     let noteId = req.params.noteId; | ||||
| @@ -20,6 +22,13 @@ router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { | ||||
|         detail = sql.getSingleResult("select * from notes where note_id = ?", [noteId]); | ||||
|     } | ||||
|  | ||||
|     if (detail.encryption > 0) { | ||||
|         const dataKey = protected_session.getDataKey(req); | ||||
|  | ||||
|         detail.note_title = data_encryption.decrypt(dataKey, detail.note_title); | ||||
|         detail.note_text = data_encryption.decrypt(dataKey, detail.note_text); | ||||
|     } | ||||
|  | ||||
|     res.send({ | ||||
|         detail: detail, | ||||
|         images: await sql.getResults("select * from images where note_id = ? order by note_offset", [noteId]), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user