removed dataKey where it's not necessary anymore (use of CLS instead)

This commit is contained in:
azivner 2018-03-31 08:53:52 -04:00
parent 5d203b2278
commit 05676f3459
12 changed files with 78 additions and 105 deletions

View File

@ -11,7 +11,7 @@ class Note extends Entity {
super(repository, row);
if (this.isProtected) {
protected_session.decryptNote(this.dataKey, this);
protected_session.decryptNote(this);
}
if (this.isJson()) {
@ -129,7 +129,7 @@ class Note extends Entity {
this.content = JSON.stringify(this.jsonContent, null, '\t');
if (this.isProtected) {
protected_session.encryptNote(this.dataKey, this);
protected_session.encryptNote(this);
}
}
}

View File

@ -37,21 +37,18 @@ async function uploadFile(req) {
async function downloadFile(req, res) {
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 ${noteId} doesn't exist.`);
}
if (note.isProtected) {
const dataKey = protected_session.getDataKeyForProtectedSessionId(protectedSessionId);
if (!dataKey) {
if (!protected_session.isProtectedSessionAvailable()) {
res.status(401).send("Protected session not available");
return;
}
protected_session.decryptNote(dataKey, note);
protected_session.decryptNote(note);
}
const labelMap = await labels.getNoteLabelMap(noteId);

View File

@ -6,7 +6,7 @@ const protected_session = require('../../services/protected_session');
async function getNoteRevisions(req) {
const noteId = req.params.noteId;
const revisions = await sql.getRows("SELECT * FROM note_revisions WHERE noteId = ? order by dateModifiedTo desc", [noteId]);
protected_session.decryptNoteRevisions(req, revisions);
protected_session.decryptNoteRevisions(revisions);
return revisions;
}

View File

@ -20,7 +20,7 @@ async function getNote(req) {
return [404, "Note " + noteId + " has not been found."];
}
protected_session.decryptNote(req, note);
protected_session.decryptNote(note);
if (note.type === 'file') {
// no need to transfer (potentially large) file payload for this request
@ -46,24 +46,21 @@ async function createNote(req) {
async function updateNote(req) {
const note = req.body;
const noteId = req.params.noteId;
const dataKey = protected_session.getDataKey(req);
await notes.updateNote(noteId, note, dataKey);
await notes.updateNote(noteId, note);
}
async function sortNotes(req) {
const noteId = req.params.noteId;
const dataKey = protected_session.getDataKey(req);
await tree.sortNotesAlphabetically(noteId, dataKey);
await tree.sortNotesAlphabetically(noteId);
}
async function protectBranch(req) {
const noteId = req.params.noteId;
const isProtected = !!parseInt(req.params.isProtected);
const dataKey = protected_session.getDataKey(req);
await notes.protectNoteRecursively(noteId, dataKey, isProtected);
await notes.protectNoteRecursively(noteId, isProtected);
}
async function setNoteTypeMime(req) {

View File

@ -45,7 +45,7 @@ async function getTree(req) {
WHERE
notes.isDeleted = 0`));
protected_session.decryptNotes(req, notes);
protected_session.decryptNotes(notes);
notes.forEach(note => {
note.hideInAutocomplete = !!note.hideInAutocomplete;

View File

@ -38,6 +38,7 @@ const router = express.Router();
const auth = require('../services/auth');
const cls = require('../services/cls');
const sql = require('../services/sql');
const protectedSessionService = require('../services/protected_session');
function apiResultHandler(res, result) {
// if it's an array and first element is integer then we consider this to be [statusCode, response] format
@ -67,6 +68,7 @@ function route(method, path, middleware, routeHandler, resultHandler) {
try {
const result = await cls.init(async () => {
cls.namespace.set('sourceId', req.headers.source_id);
protectedSessionService.setProtectedSessionId(req);
return await sql.doInTransaction(async () => {
return await routeHandler(req, res, next);

View File

@ -5,7 +5,7 @@ const sync_table = require('./sync_table');
const labels = require('./labels');
const protected_session = require('./protected_session');
async function createNewNote(parentNoteId, noteOpts, dataKey) {
async function createNewNote(parentNoteId, noteOpts) {
const noteId = utils.newNoteId();
const branchId = utils.newBranchId();
@ -57,7 +57,7 @@ async function createNewNote(parentNoteId, noteOpts, dataKey) {
};
if (note.isProtected) {
protected_session.encryptNote(dataKey, note);
protected_session.encryptNote(note);
}
await sql.insert("notes", note);
@ -106,7 +106,7 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {})
note.mime = "text/html";
}
const {noteId} = await createNewNote(parentNoteId, note, extraOptions.dataKey);
const {noteId} = await createNewNote(parentNoteId, note);
if (extraOptions.labels) {
for (const attrName in extraOptions.labels) {
@ -117,30 +117,30 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {})
return noteId;
}
async function protectNoteRecursively(noteId, dataKey, protect) {
async function protectNoteRecursively(noteId, protect) {
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
await protectNote(note, dataKey, protect);
await protectNote(note, protect);
const children = await sql.getColumn("SELECT noteId FROM branches WHERE parentNoteId = ? AND isDeleted = 0", [noteId]);
for (const childNoteId of children) {
await protectNoteRecursively(childNoteId, dataKey, protect);
await protectNoteRecursively(childNoteId, protect);
}
}
async function protectNote(note, dataKey, protect) {
async function protectNote(note, protect) {
let changed = false;
if (protect && !note.isProtected) {
protected_session.encryptNote(dataKey, note);
protected_session.encryptNote(note);
note.isProtected = true;
changed = true;
}
else if (!protect && note.isProtected) {
protected_session.decryptNote(dataKey, note);
protected_session.decryptNote(note);
note.isProtected = false;
@ -154,20 +154,20 @@ async function protectNote(note, dataKey, protect) {
await sync_table.addNoteSync(note.noteId);
}
await protectNoteRevisions(note.noteId, dataKey, protect);
await protectNoteRevisions(note.noteId, protect);
}
async function protectNoteRevisions(noteId, dataKey, protect) {
async function protectNoteRevisions(noteId, protect) {
const revisionsToChange = await sql.getRows("SELECT * FROM note_revisions WHERE noteId = ? AND isProtected != ?", [noteId, protect]);
for (const revision of revisionsToChange) {
if (protect) {
protected_session.encryptNoteRevision(dataKey, revision);
protected_session.encryptNoteRevision(revision);
revision.isProtected = true;
}
else {
protected_session.decryptNoteRevision(dataKey, revision);
protected_session.decryptNoteRevision(revision);
revision.isProtected = false;
}
@ -179,7 +179,7 @@ async function protectNoteRevisions(noteId, dataKey, protect) {
}
}
async function saveNoteRevision(noteId, dataKey, nowStr) {
async function saveNoteRevision(noteId, nowStr) {
const oldNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
if (oldNote.type === 'file') {
@ -187,7 +187,7 @@ async function saveNoteRevision(noteId, dataKey, nowStr) {
}
if (oldNote.isProtected) {
protected_session.decryptNote(dataKey, oldNote);
protected_session.decryptNote(oldNote);
oldNote.isProtected = false;
}
@ -255,23 +255,23 @@ async function saveNoteImages(noteId, noteText) {
}
}
async function loadFile(noteId, newNote, dataKey) {
async function loadFile(noteId, newNote) {
const oldNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
if (oldNote.isProtected) {
await protected_session.decryptNote(dataKey, oldNote);
await protected_session.decryptNote(oldNote);
}
newNote.content = oldNote.content;
}
async function updateNote(noteId, newNote, dataKey) {
async function updateNote(noteId, newNote) {
if (newNote.type === 'file') {
await loadFile(noteId, newNote, dataKey);
await loadFile(noteId, newNote);
}
if (newNote.isProtected) {
await protected_session.encryptNote(dataKey, newNote);
await protected_session.encryptNote(newNote);
}
const labelsMap = await labels.getNoteLabelMap(noteId);
@ -293,12 +293,12 @@ async function updateNote(noteId, newNote, dataKey) {
&& !existingnoteRevisionId
&& msSinceDateCreated >= noteRevisionSnapshotTimeInterval * 1000) {
await saveNoteRevision(noteId, dataKey, nowStr);
await saveNoteRevision(noteId, nowStr);
}
await saveNoteImages(noteId, newNote.content);
await protectNoteRevisions(noteId, dataKey, newNote.isProtected);
await protectNoteRevisions(noteId, newNote.isProtected);
await sql.execute("UPDATE notes SET title = ?, content = ?, isProtected = ?, dateModified = ? WHERE noteId = ?", [
newNote.title,

View File

@ -2,50 +2,43 @@
const utils = require('./utils');
const data_encryption = require('./data_encryption');
const session = {};
const dataKeyMap = {};
const cls = require('./cls');
function setDataKey(req, decryptedDataKey) {
session.decryptedDataKey = Array.from(decryptedDataKey); // can't store buffer in session
session.protectedSessionId = utils.randomSecureToken(32);
const protectedSessionId = utils.randomSecureToken(32);
return session.protectedSessionId;
dataKeyMap[protectedSessionId] = Array.from(decryptedDataKey); // can't store buffer in session
return protectedSessionId;
}
function getProtectedSessionId(req) {
return req.headers.protected_session_id;
function setProtectedSessionId(req) {
cls.namespace.set('protectedSessionId', req.headers.protected_session_id);
}
/**
* @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;
}
function getProtectedSessionId() {
return cls.namespace.get('protectedSessionId');
}
const protectedSessionId = getProtectedSessionId(obj);
function getDataKey() {
const protectedSessionId = getProtectedSessionId();
return getDataKeyForProtectedSessionId(protectedSessionId);
return dataKeyMap[protectedSessionId];
}
function getDataKeyForProtectedSessionId(protectedSessionId) {
if (protectedSessionId && session.protectedSessionId === protectedSessionId) {
return session.decryptedDataKey;
}
else {
return null;
}
return dataKeyMap[protectedSessionId];
}
function isProtectedSessionAvailable(req) {
const protectedSessionId = getProtectedSessionId(req);
return protectedSessionId && session.protectedSessionId === protectedSessionId;
return !!dataKeyMap[protectedSessionId];
}
function decryptNote(dataKey, note) {
dataKey = getDataKey(dataKey);
function decryptNote(note) {
const dataKey = getDataKey();
if (!note.isProtected) {
return;
@ -67,16 +60,16 @@ function decryptNote(dataKey, note) {
}
}
function decryptNotes(dataKey, notes) {
dataKey = getDataKey(dataKey);
function decryptNotes(notes) {
const dataKey = getDataKey();
for (const note of notes) {
decryptNote(dataKey, note);
decryptNote(note);
}
}
function decryptNoteRevision(dataKey, hist) {
dataKey = getDataKey(dataKey);
function decryptNoteRevision(hist) {
const dataKey = getDataKey();
if (!hist.isProtected) {
return;
@ -91,23 +84,21 @@ function decryptNoteRevision(dataKey, hist) {
}
}
function decryptNoteRevisions(dataKey, noteRevisions) {
dataKey = getDataKey(dataKey);
function decryptNoteRevisions(noteRevisions) {
for (const revision of noteRevisions) {
decryptNoteRevision(dataKey, revision);
decryptNoteRevision(revision);
}
}
function encryptNote(dataKey, note) {
dataKey = getDataKey(dataKey);
function encryptNote(note) {
const dataKey = getDataKey();
note.title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(note.noteId), note.title);
note.content = data_encryption.encrypt(dataKey, data_encryption.noteContentIv(note.noteId), note.content);
}
function encryptNoteRevision(dataKey, revision) {
dataKey = getDataKey(dataKey);
function encryptNoteRevision(revision) {
const dataKey = getDataKey();
revision.title = data_encryption.encrypt(dataKey, data_encryption.noteTitleIv(revision.noteRevisionId), revision.title);
revision.content = data_encryption.encrypt(dataKey, data_encryption.noteContentIv(revision.noteRevisionId), revision.content);
@ -123,5 +114,6 @@ module.exports = {
decryptNoteRevision,
decryptNoteRevisions,
encryptNote,
encryptNoteRevision
encryptNoteRevision,
setProtectedSessionId
};

View File

@ -7,17 +7,9 @@ const Label = require('../entities/label');
const sync_table = require('../services/sync_table');
class Repository {
constructor(dataKey) {
this.dataKey = protected_session.getDataKey(dataKey);
}
async getEntities(query, params = []) {
const rows = await sql.getRows(query, params);
for (const row of rows) {
row.dataKey = this.dataKey;
}
return rows.map(row => this.createEntityFromRow(row));
}
@ -28,8 +20,6 @@ class Repository {
return null;
}
row.dataKey = this.dataKey;
return this.createEntityFromRow(row);
}
@ -66,7 +56,6 @@ class Repository {
const clone = Object.assign({}, entity);
delete clone.dataKey;
delete clone.jsonContent;
delete clone.repository;

View File

@ -2,17 +2,17 @@ const sql = require('./sql');
const ScriptContext = require('./script_context');
const Repository = require('./repository');
async function executeNote(dataKey, note) {
async function executeNote(note) {
if (!note.isJavaScript()) {
return;
}
const bundle = await getScriptBundle(note);
await executeBundle(dataKey, bundle);
await executeBundle(bundle);
}
async function executeBundle(dataKey, bundle, startNote) {
async function executeBundle(bundle, startNote) {
if (!startNote) {
// this is the default case, the only exception is when we want to preserve frontend startNote
startNote = bundle.note;
@ -21,7 +21,7 @@ async function executeBundle(dataKey, bundle, startNote) {
// last \r\n is necessary if script contains line comment on its last line
const script = "async function() {\r\n" + bundle.script + "\r\n}";
const ctx = new ScriptContext(dataKey, startNote, bundle.allNotes);
const ctx = new ScriptContext(startNote, bundle.allNotes);
if (await bundle.note.hasLabel('manual_transaction_handling')) {
return await execute(ctx, script, '');
@ -35,8 +35,8 @@ async function executeBundle(dataKey, bundle, startNote) {
* This method preserves frontend startNode - that's why we start execution from currentNote and override
* bundle's startNote.
*/
async function executeScript(dataKey, script, params, startNoteId, currentNoteId) {
const repository = new Repository(dataKey);
async function executeScript(script, params, startNoteId, currentNoteId) {
const repository = new Repository();
const startNote = await repository.getNote(startNoteId);
const currentNote = await repository.getNote(currentNoteId);
@ -46,7 +46,7 @@ async function executeScript(dataKey, script, params, startNoteId, currentNoteId
const bundle = await getScriptBundle(currentNote);
return await executeBundle(dataKey, bundle, startNote);
return await executeBundle(bundle, startNote);
}
async function execute(ctx, script, paramsStr) {

View File

@ -9,12 +9,10 @@ const config = require('./config');
const Repository = require('./repository');
const axios = require('axios');
function ScriptContext(dataKey, startNote, allNotes) {
dataKey = protected_session.getDataKey(dataKey);
function ScriptContext(startNote, allNotes) {
this.modules = {};
this.notes = utils.toObject(allNotes, note => [note.noteId, note]);
this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(dataKey, startNote, note)]);
this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(startNote, note)]);
this.require = moduleNoteIds => {
return moduleName => {
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));
@ -29,8 +27,8 @@ function ScriptContext(dataKey, startNote, allNotes) {
};
}
function ScriptApi(dataKey, startNote, currentNote) {
const repository = new Repository(dataKey);
function ScriptApi(startNote, currentNote) {
const repository = new Repository();
this.startNote = startNote;
this.currentNote = currentNote;
@ -59,8 +57,6 @@ function ScriptApi(dataKey, startNote, currentNote) {
};
this.createNote = async function(parentNoteId, title, content = "", extraOptions = {}) {
extraOptions.dataKey = dataKey;
return await notes.createNote(parentNoteId, title, content, extraOptions);
};

View File

@ -76,13 +76,13 @@ async function loadSubTreeNoteIds(parentNoteId, subTreeNoteIds) {
}
}
async function sortNotesAlphabetically(parentNoteId, req) {
async function sortNotesAlphabetically(parentNoteId) {
await sql.doInTransaction(async () => {
const notes = await sql.getRows(`SELECT branchId, noteId, title, isProtected
FROM notes JOIN branches USING(noteId)
WHERE branches.isDeleted = 0 AND parentNoteId = ?`, [parentNoteId]);
protected_session.decryptNotes(req, notes);
protected_session.decryptNotes(notes);
notes.sort((a, b) => a.title.toLowerCase() < b.title.toLowerCase() ? -1 : 1);