refactoring / unification of note encryption / decryption

This commit is contained in:
azivner 2018-01-24 22:13:41 -05:00
parent 18709eb340
commit 74fff39c3f
7 changed files with 105 additions and 69 deletions

View file

@ -4,7 +4,6 @@ const express = require('express');
const router = express.Router();
const sql = require('../../services/sql');
const auth = require('../../services/auth');
const data_encryption = require('../../services/data_encryption');
const protected_session = require('../../services/protected_session');
const sync_table = require('../../services/sync_table');
const wrap = require('express-promise-wrap').wrap;
@ -12,15 +11,7 @@ const wrap = require('express-promise-wrap').wrap;
router.get('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
const noteId = req.params.noteId;
const history = await sql.getAll("SELECT * FROM notes_history WHERE note_id = ? order by date_modified_to desc", [noteId]);
const dataKey = protected_session.getDataKey(req);
for (const hist of history) {
if (hist.is_protected) {
hist.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(hist.note_history_id), hist.note_title);
hist.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(hist.note_history_id), hist.note_text);
}
}
protected_session.decryptNoteHistoryRows(req, history);
res.send(history);
}));

View file

@ -24,12 +24,7 @@ router.get('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
return res.status(404).send({});
}
if (detail.is_protected) {
const dataKey = protected_session.getDataKey(req);
detail.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(detail.note_id), detail.note_title);
detail.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(detail.note_id), detail.note_text);
}
protected_session.decryptNote(req, detail);
res.send({
detail: detail

View file

@ -7,7 +7,6 @@ const wrap = require('express-promise-wrap').wrap;
const log = require('../../services/log');
const sql = require('../../services/sql');
const protected_session = require('../../services/protected_session');
const data_encryption = require('../../services/data_encryption');
router.post('/exec', auth.checkApiAuth, wrap(async (req, res, next) => {
log.info('Executing script: ' + req.body.script);
@ -22,21 +21,21 @@ router.post('/exec', auth.checkApiAuth, wrap(async (req, res, next) => {
router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
const noteId = req.params.noteId;
const dataKey = protected_session.getDataKey(req);
res.send(await getSubTreeScripts(noteId, [noteId], dataKey));
res.send(await getSubTreeScripts(noteId, [noteId], req));
}));
async function getSubTreeScripts(parentId, includedNoteIds, dataKey) {
const childs = await sql.getAll(`SELECT notes.note_id, notes.note_title, notes.note_text, notes.is_protected
const children = await sql.getAll(`SELECT notes.note_id, notes.note_title, notes.note_text, notes.is_protected
FROM notes JOIN notes_tree USING(note_id)
WHERE notes_tree.is_deleted = 0 AND notes.is_deleted = 0
AND notes_tree.parent_note_id = ? AND notes.type = 'code'
AND (notes.mime = 'application/javascript' OR notes.mime = 'text/html')`, [parentId]);
protected_session.decryptNotes(dataKey, children);
let script = "\r\n";
for (const child of childs) {
for (const child of children) {
if (includedNoteIds.includes(child.note_id)) {
return;
}
@ -45,15 +44,6 @@ async function getSubTreeScripts(parentId, includedNoteIds, dataKey) {
script += await getSubTreeScripts(child.note_id, includedNoteIds, dataKey);
if (child.is_protected) {
if (!dataKey) {
throw new Error("Protected note is included, but script isn't running in protected session.");
}
child.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(child.note_id), child.note_title);
child.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(child.note_id), child.note_text);
}
script += child.note_text + "\r\n";
}

View file

@ -7,7 +7,6 @@ const options = require('../../services/options');
const utils = require('../../services/utils');
const auth = require('../../services/auth');
const protected_session = require('../../services/protected_session');
const data_encryption = require('../../services/data_encryption');
const sync_table = require('../../services/sync_table');
const wrap = require('express-promise-wrap').wrap;
@ -27,13 +26,7 @@ router.get('/', auth.checkApiAuth, wrap(async (req, res, next) => {
ORDER BY
note_position`);
const dataKey = protected_session.getDataKey(req);
for (const note of notes) {
if (note.is_protected) {
note.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
}
}
protected_session.decryptNotes(req, notes);
res.send({
notes: notes,

View file

@ -5,6 +5,7 @@ const notes = require('./notes');
const data_encryption = require('./data_encryption');
const sync_table = require('./sync_table');
const attributes = require('./attributes');
const protected_session = require('./protected_session');
async function createNewNote(parentNoteId, note, sourceId) {
const noteId = utils.newNoteId();
@ -67,11 +68,6 @@ async function createNewNote(parentNoteId, note, sourceId) {
};
}
async function encryptNote(note, dataKey) {
note.detail.note_title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(note.detail.note_id), note.detail.note_title);
note.detail.note_text = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(note.detail.note_id), note.detail.note_text);
}
async function protectNoteRecursively(noteId, dataKey, protect, sourceId) {
const note = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]);
@ -84,24 +80,20 @@ async function protectNoteRecursively(noteId, dataKey, protect, sourceId) {
}
}
function decryptNote(note, dataKey) {
note.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
note.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(note.note_id), note.note_text);
note.is_protected = false;
}
async function protectNote(note, dataKey, protect, sourceId) {
let changed = false;
if (protect && !note.is_protected) {
note.note_title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
note.note_text = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(note.note_id), note.note_text);
protected_session.encryptNote(dataKey, note);
note.is_protected = true;
changed = true;
}
else if (!protect && note.is_protected) {
decryptNote(note, dataKey);
protected_session.decryptNote(dataKey, note);
note.is_protected = false;
changed = true;
}
@ -121,13 +113,13 @@ async function protectNoteHistory(noteId, dataKey, protect, sourceId) {
for (const history of historyToChange) {
if (protect) {
history.note_title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(history.note_history_id), history.note_title);
history.note_text = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(history.note_history_id), history.note_text);
protected_session.encryptNoteHistoryRow(dataKey, history);
history.is_protected = true;
}
else {
history.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(history.note_history_id), history.note_title);
history.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(history.note_history_id), history.note_text);
protected_session.decryptNoteHistoryRow(dataKey, history);
history.is_protected = false;
}
@ -142,7 +134,9 @@ async function saveNoteHistory(noteId, dataKey, sourceId, nowStr) {
const oldNote = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]);
if (oldNote.is_protected) {
decryptNote(oldNote, dataKey);
protected_session.decryptNote(dataKey, oldNote);
note.is_protected = false;
}
const newNoteHistoryId = utils.newNoteHistoryId();
@ -210,11 +204,11 @@ async function saveNoteImages(noteId, noteText, sourceId) {
async function updateNote(noteId, newNote, dataKey, sourceId) {
if (newNote.detail.note_text === '<p>&nbsp;</p>') {
newNote.detail.note_text = '';
newNote.detail.note_text = ''
}
if (newNote.detail.is_protected) {
await encryptNote(newNote, dataKey);
await protected_session.encryptNote(dataKey, newNote.detail);
}
const attributesMap = await attributes.getNoteAttributeMap(noteId);

View file

@ -1,6 +1,7 @@
"use strict";
const utils = require('./utils');
const data_encryption = require('./data_encryption');
const session = {};
function setDataKey(req, decryptedDataKey) {
@ -14,8 +15,16 @@ function getProtectedSessionId(req) {
return req.headers.protected_session_id;
}
function getDataKey(req) {
const protectedSessionId = getProtectedSessionId(req);
/**
* @param obj - can be either array, in that case it's considered to be already dataKey and we just return it
* if it's not a array, we consider it a request object and try to pull dataKey based on the session id header
*/
function getDataKey(obj) {
if (!obj || obj.constructor.name === 'Array') {
return obj;
}
const protectedSessionId = getProtectedSessionId(obj);
if (protectedSessionId && session.protectedSessionId === protectedSessionId) {
return session.decryptedDataKey;
@ -31,8 +40,76 @@ function isProtectedSessionAvailable(req) {
return protectedSessionId && session.protectedSessionId === protectedSessionId;
}
function decryptNote(dataKey, note) {
dataKey = getDataKey(dataKey);
if (!note.is_protected) {
return;
}
if (note.note_title) {
note.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
}
if (note.note_text) {
note.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(note.note_id), note.note_text);
}
}
function decryptNotes(dataKey, notes) {
dataKey = getDataKey(dataKey);
for (const note of notes) {
decryptNote(dataKey, note);
}
}
function decryptNoteHistoryRow(dataKey, hist) {
dataKey = getDataKey(dataKey);
if (!hist.is_protected) {
return;
}
if (hist.note_title) {
hist.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(hist.note_history_id), hist.note_title);
}
if (hist.note_text) {
hist.note_text = data_encryption.decryptString(dataKey, data_encryption.noteTextIv(hist.note_history_id), hist.note_text);
}
}
function decryptNoteHistoryRows(dataKey, historyRows) {
dataKey = getDataKey(dataKey);
for (const hist of historyRows) {
decryptNoteHistoryRow(dataKey, hist);
}
}
function encryptNote(dataKey, note) {
dataKey = getDataKey(dataKey);
note.note_title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
note.note_text = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(note.note_id), note.note_text);
}
function encryptNoteHistoryRow(dataKey, history) {
dataKey = getDataKey(dataKey);
history.note_title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(history.note_history_id), history.note_title);
history.note_text = data_encryption.encrypt(dataKey, data_encryption.noteTextIv(history.note_history_id), history.note_text);
}
module.exports = {
setDataKey,
getDataKey,
isProtectedSessionAvailable
isProtectedSessionAvailable,
decryptNote,
decryptNotes,
decryptNoteHistoryRow,
decryptNoteHistoryRows,
encryptNote,
encryptNoteHistoryRow
};

View file

@ -80,17 +80,13 @@ async function loadSubTreeNoteIds(parentNoteId, subTreeNoteIds) {
}
}
async function sortNotesAlphabetically(parentNoteId, dataKey, sourceId) {
async function sortNotesAlphabetically(parentNoteId, req, sourceId) {
await sql.doInTransaction(async () => {
const notes = await sql.getAll(`SELECT note_tree_id, note_id, note_title, is_protected
FROM notes JOIN notes_tree USING(note_id)
WHERE notes_tree.is_deleted = 0 AND parent_note_id = ?`, [parentNoteId]);
for (const note of notes) {
if (note.is_protected) {
note.note_title = data_encryption.decryptString(dataKey, data_encryption.noteTitleIv(note.note_id), note.note_title);
}
}
protected_session.decryptNotes(req, notes);
notes.sort((a, b) => a.note_title.toLowerCase() < b.note_title.toLowerCase() ? -1 : 1);