mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
server side encryption WIP
This commit is contained in:
parent
ec49bf0cca
commit
50b789fc39
@ -91,8 +91,6 @@ settings.addModule((function() {
|
|||||||
|
|
||||||
// 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
|
||||||
encryption.resetEncryptionSession();
|
encryption.resetEncryptionSession();
|
||||||
|
|
||||||
encryption.setEncryptedDataKey(result.new_encrypted_data_key);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
showError(result.message);
|
showError(result.message);
|
||||||
|
@ -23,10 +23,6 @@ const encryption = (function() {
|
|||||||
encryptedDataKey = settings.encrypted_data_key;
|
encryptedDataKey = settings.encrypted_data_key;
|
||||||
});
|
});
|
||||||
|
|
||||||
function setEncryptedDataKey(encDataKey) {
|
|
||||||
encryptedDataKey = encDataKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEncryptionSessionTimeout(encSessTimeout) {
|
function setEncryptionSessionTimeout(encSessTimeout) {
|
||||||
encryptionSessionTimeout = encSessTimeout;
|
encryptionSessionTimeout = encSessTimeout;
|
||||||
}
|
}
|
||||||
@ -34,7 +30,7 @@ const encryption = (function() {
|
|||||||
function ensureEncryptionIsAvailable(requireEncryption, modal) {
|
function ensureEncryptionIsAvailable(requireEncryption, modal) {
|
||||||
const dfd = $.Deferred();
|
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
|
// if this is entry point then we need to show the app even before the note is loaded
|
||||||
showAppIfHidden();
|
showAppIfHidden();
|
||||||
|
|
||||||
@ -58,54 +54,6 @@ const encryption = (function() {
|
|||||||
return dfd.promise();
|
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() {
|
async function setupEncryptionSession() {
|
||||||
const password = encryptionPasswordEl.val();
|
const password = encryptionPasswordEl.val();
|
||||||
encryptionPasswordEl.val("");
|
encryptionPasswordEl.val("");
|
||||||
@ -122,6 +70,7 @@ const encryption = (function() {
|
|||||||
|
|
||||||
dialogEl.dialog("close");
|
dialogEl.dialog("close");
|
||||||
|
|
||||||
|
noteEditor.reload();
|
||||||
noteTree.reload();
|
noteTree.reload();
|
||||||
|
|
||||||
if (encryptionDeferred !== null) {
|
if (encryptionDeferred !== null) {
|
||||||
@ -158,7 +107,7 @@ const encryption = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isEncryptionAvailable() {
|
function isEncryptionAvailable() {
|
||||||
return dataKey !== null;
|
return protectedSessionId !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDataAes() {
|
function getDataAes() {
|
||||||
@ -167,10 +116,6 @@ const encryption = (function() {
|
|||||||
return new aesjs.ModeOfOperation.ctr(dataKey, new aesjs.Counter(5));
|
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) {
|
function encryptNoteIfNecessary(note) {
|
||||||
if (note.detail.encryption === 0) {
|
if (note.detail.encryption === 0) {
|
||||||
return note;
|
return note;
|
||||||
@ -307,17 +252,6 @@ const encryption = (function() {
|
|||||||
noteEditor.setNoteBackgroundIfEncrypted(note);
|
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) {
|
async function encryptSubTree(noteId) {
|
||||||
await ensureEncryptionIsAvailable(true, true);
|
await ensureEncryptionIsAvailable(true, true);
|
||||||
|
|
||||||
@ -433,10 +367,8 @@ const encryption = (function() {
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setEncryptedDataKey,
|
|
||||||
setEncryptionSessionTimeout,
|
setEncryptionSessionTimeout,
|
||||||
ensureEncryptionIsAvailable,
|
ensureEncryptionIsAvailable,
|
||||||
decryptTreeItems,
|
|
||||||
resetEncryptionSession,
|
resetEncryptionSession,
|
||||||
isEncryptionAvailable,
|
isEncryptionAvailable,
|
||||||
encryptNoteIfNecessary,
|
encryptNoteIfNecessary,
|
||||||
@ -444,7 +376,6 @@ const encryption = (function() {
|
|||||||
decryptString,
|
decryptString,
|
||||||
encryptNoteAndSendToServer,
|
encryptNoteAndSendToServer,
|
||||||
decryptNoteAndSendToServer,
|
decryptNoteAndSendToServer,
|
||||||
decryptNoteIfNecessary,
|
|
||||||
encryptSubTree,
|
encryptSubTree,
|
||||||
decryptSubTree,
|
decryptSubTree,
|
||||||
getProtectedSessionId
|
getProtectedSessionId
|
||||||
|
@ -209,8 +209,6 @@ const noteEditor = (function() {
|
|||||||
|
|
||||||
encryptionPasswordEl.val('');
|
encryptionPasswordEl.val('');
|
||||||
|
|
||||||
encryption.decryptNoteIfNecessary(currentNote);
|
|
||||||
|
|
||||||
noteTitleEl.val(currentNote.detail.note_title);
|
noteTitleEl.val(currentNote.detail.note_title);
|
||||||
|
|
||||||
noteChangeDisabled = true;
|
noteChangeDisabled = true;
|
||||||
@ -234,12 +232,6 @@ 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 && !encryption.isEncryptionAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
encryption.decryptNoteIfNecessary(note);
|
|
||||||
|
|
||||||
return note;
|
return note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,8 +190,6 @@ const noteTree = (function() {
|
|||||||
|
|
||||||
// this will also reload the note content
|
// this will also reload the note content
|
||||||
await treeEl.fancytree('getTree').reload(treeResp.notes);
|
await treeEl.fancytree('getTree').reload(treeResp.notes);
|
||||||
|
|
||||||
encryption.decryptTreeItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTree() {
|
function loadTree() {
|
||||||
|
@ -7,6 +7,8 @@ const sql = require('../../services/sql');
|
|||||||
const options = require('../../services/options');
|
const options = require('../../services/options');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const notes = require('../../services/notes');
|
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) => {
|
router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => {
|
||||||
let noteId = req.params.noteId;
|
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]);
|
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({
|
res.send({
|
||||||
detail: detail,
|
detail: detail,
|
||||||
images: await sql.getResults("select * from images where note_id = ? order by note_offset", [noteId]),
|
images: await sql.getResults("select * from images where note_id = ? order by note_offset", [noteId]),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user