diff --git a/src/public/javascripts/note_editor.js b/src/public/javascripts/note_editor.js index c742c8551..216ba3e48 100644 --- a/src/public/javascripts/note_editor.js +++ b/src/public/javascripts/note_editor.js @@ -329,7 +329,8 @@ const noteEditor = (function() { const url = new URL(window.location.href); const host = url.protocol + "//" + url.hostname + ":" + url.port; - const downloadUrl = "/api/attachments/download/" + getCurrentNoteId(); + const downloadUrl = "/api/attachments/download/" + getCurrentNoteId() + + "?protectedSessionId=" + encodeURIComponent(protected_session.getProtectedSessionId()); return host + downloadUrl; } diff --git a/src/routes/api/attachments.js b/src/routes/api/attachments.js index f319f11a6..dfa3822a0 100644 --- a/src/routes/api/attachments.js +++ b/src/routes/api/attachments.js @@ -6,6 +6,7 @@ const sql = require('../../services/sql'); const auth = require('../../services/auth'); const notes = require('../../services/notes'); const attributes = require('../../services/attributes'); +const protected_session = require('../../services/protected_session'); const multer = require('multer')(); const wrap = require('express-promise-wrap').wrap; @@ -44,9 +45,21 @@ router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single( router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => { const noteId = req.params.noteId; const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); + const protectedSessionId = req.query.protectedSessionId; if (!note) { - return res.status(404).send(`Note ${parentNoteId} doesn't exist.`); + return res.status(404).send(`Note ${noteId} doesn't exist.`); + } + + if (note.isProtected) { + const dataKey = protected_session.getDataKeyForProtectedSessionId(protectedSessionId); + + if (!dataKey) { + res.status(401).send("Protected session not available"); + return; + } + + protected_session.decryptNote(dataKey, note); } const attributeMap = await attributes.getNoteAttributeMap(noteId); diff --git a/src/services/data_encryption.js b/src/services/data_encryption.js index 4de137972..f2b2beabf 100644 --- a/src/services/data_encryption.js +++ b/src/services/data_encryption.js @@ -88,7 +88,7 @@ function noteTitleIv(iv) { return "0" + iv; } -function noteTextIv(iv) { +function noteContentIv(iv) { return "1" + iv; } @@ -97,5 +97,5 @@ module.exports = { decrypt, decryptString, noteTitleIv, - noteTextIv + noteContentIv }; \ No newline at end of file diff --git a/src/services/notes.js b/src/services/notes.js index fe8390b9b..45cf16538 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -148,10 +148,14 @@ async function protectNoteHistory(noteId, dataKey, protect, sourceId) { async function saveNoteHistory(noteId, dataKey, sourceId, nowStr) { const oldNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); + if (oldNote.type === 'file') { + return; + } + if (oldNote.isProtected) { protected_session.decryptNote(dataKey, oldNote); - note.isProtected = false; + oldNote.isProtected = false; } const newNoteRevisionId = utils.newNoteRevisionId(); @@ -217,7 +221,21 @@ async function saveNoteImages(noteId, noteText, sourceId) { } } +async function loadFile(noteId, newNote, dataKey) { + const oldNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]); + + if (oldNote.isProtected) { + await protected_session.decryptNote(dataKey, oldNote); + } + + newNote.detail.content = oldNote.content; +} + async function updateNote(noteId, newNote, dataKey, sourceId) { + if (newNote.detail.type === 'file') { + await loadFile(noteId, newNote, dataKey); + } + if (newNote.detail.isProtected) { await protected_session.encryptNote(dataKey, newNote.detail); } diff --git a/src/services/protected_session.js b/src/services/protected_session.js index 5abe9d477..435928050 100644 --- a/src/services/protected_session.js +++ b/src/services/protected_session.js @@ -26,6 +26,10 @@ function getDataKey(obj) { const protectedSessionId = getProtectedSessionId(obj); + return getDataKeyForProtectedSessionId(protectedSessionId); +} + +function getDataKeyForProtectedSessionId(protectedSessionId) { if (protectedSessionId && session.protectedSessionId === protectedSessionId) { return session.decryptedDataKey; } @@ -52,7 +56,14 @@ function decryptNote(dataKey, note) { } if (note.content) { - note.content = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(note.noteId), note.content); + const contentIv = data_encryption.noteContentIv(note.noteId); + + if (note.type === 'file') { + note.content = data_encryption.decrypt(dataKey, contentIv, note.content); + } + else { + note.content = data_encryption.decryptString(dataKey, contentIv, note.content); + } } } @@ -76,7 +87,7 @@ function decryptNoteHistoryRow(dataKey, hist) { } if (hist.content) { - hist.content = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(hist.noteRevisionId), hist.content); + hist.content = data_encryption.decryptString(dataKey, data_encryption.noteContentIv(hist.noteRevisionId), hist.content); } } @@ -92,19 +103,20 @@ function encryptNote(dataKey, note) { dataKey = getDataKey(dataKey); note.title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(note.noteId), note.title); - note.content = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(note.noteId), note.content); + note.content = data_encryption.encrypt(dataKey, data_encryption.noteContentIv(note.noteId), note.content); } function encryptNoteHistoryRow(dataKey, history) { dataKey = getDataKey(dataKey); history.title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(history.noteRevisionId), history.title); - history.content = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(history.noteRevisionId), history.content); + history.content = data_encryption.encrypt(dataKey, data_encryption.noteContentIv(history.noteRevisionId), history.content); } module.exports = { setDataKey, getDataKey, + getDataKeyForProtectedSessionId, isProtectedSessionAvailable, decryptNote, decryptNotes,