protect/unprotect subtree

This commit is contained in:
azivner 2017-11-15 00:04:26 -05:00
parent c2ad14ba18
commit 9cf935efd1
5 changed files with 109 additions and 29 deletions

View File

@ -31,8 +31,8 @@ const contextMenu = (function() {
{title: "Insert child note", cmd: "insertChildNote", uiIcon: "ui-icon-pencil"}, {title: "Insert child note", cmd: "insertChildNote", uiIcon: "ui-icon-pencil"},
{title: "Delete", cmd: "delete", uiIcon: "ui-icon-trash"}, {title: "Delete", cmd: "delete", uiIcon: "ui-icon-trash"},
{title: "----"}, {title: "----"},
{title: "Encrypt sub-tree", cmd: "encryptSubTree", uiIcon: "ui-icon-locked"}, {title: "Protect sub-tree", cmd: "protectSubTree", uiIcon: "ui-icon-locked"},
{title: "Decrypt sub-tree", cmd: "decryptSubTree", uiIcon: "ui-icon-unlocked"}, {title: "Unprotect sub-tree", cmd: "unprotectSubTree", uiIcon: "ui-icon-unlocked"},
{title: "----"}, {title: "----"},
{title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors"}, {title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors"},
{title: "Copy / clone", cmd: "copy", uiIcon: "ui-icon-copy"}, {title: "Copy / clone", cmd: "copy", uiIcon: "ui-icon-copy"},
@ -45,6 +45,9 @@ const contextMenu = (function() {
treeEl.contextmenu("enableEntry", "pasteAfter", noteTree.getClipboardNoteId() !== null); treeEl.contextmenu("enableEntry", "pasteAfter", noteTree.getClipboardNoteId() !== null);
treeEl.contextmenu("enableEntry", "pasteInto", noteTree.getClipboardNoteId() !== null); treeEl.contextmenu("enableEntry", "pasteInto", noteTree.getClipboardNoteId() !== null);
treeEl.contextmenu("enableEntry", "protectSubTree", protected_session.isProtectedSessionAvailable());
treeEl.contextmenu("enableEntry", "unprotectSubTree", protected_session.isProtectedSessionAvailable());
// Activate node on right-click // Activate node on right-click
node.setActive(); node.setActive();
// Disable tree keyboard handling // Disable tree keyboard handling
@ -64,11 +67,11 @@ const contextMenu = (function() {
else if (ui.cmd === "insertChildNote") { else if (ui.cmd === "insertChildNote") {
noteEditor.createNote(node, node.key, 'into'); noteEditor.createNote(node, node.key, 'into');
} }
else if (ui.cmd === "encryptSubTree") { else if (ui.cmd === "protectSubTree") {
protected_session.encryptSubTree(node.key); protected_session.protectSubTree(node.key, true);
} }
else if (ui.cmd === "decryptSubTree") { else if (ui.cmd === "unprotectSubTree") {
protected_session.decryptSubTree(node.key); protected_session.protectSubTree(node.key, false);
} }
else if (ui.cmd === "cut") { else if (ui.cmd === "cut") {
cut(node); cut(node);

View File

@ -147,6 +147,20 @@ const protected_session = (function() {
} }
} }
async function protectSubTree(noteId, protect) {
await $.ajax({
url: baseApiUrl + 'tree/' + noteId + "/protectSubTree/" + (protect ? 1 : 0),
type: 'PUT',
contentType: 'application/json',
error: () => showError("Request to un/protect sub tree has failed.")
});
showMessage("Request to un/protect sub tree has finished successfully");
noteTree.reload();
noteEditor.reload();
}
passwordFormEl.submit(() => { passwordFormEl.submit(() => {
setupProtectedSession(); setupProtectedSession();
@ -167,6 +181,7 @@ const protected_session = (function() {
protectNoteAndSendToServer, protectNoteAndSendToServer,
unprotectNoteAndSendToServer, unprotectNoteAndSendToServer,
getProtectedSessionId, getProtectedSessionId,
touchProtectedSession touchProtectedSession,
protectSubTree
}; };
})(); })();

View File

@ -12,11 +12,11 @@ const data_encryption = require('../../services/data_encryption');
const RequestContext = require('../../services/request_context'); const RequestContext = require('../../services/request_context');
router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => {
let noteId = req.params.noteId; const noteId = req.params.noteId;
await options.setOption('start_node', noteId); await options.setOption('start_node', noteId);
let detail = await sql.getSingleResult("select * from notes where note_id = ?", [noteId]); const detail = await sql.getSingleResult("select * from notes where note_id = ?", [noteId]);
if (detail.is_protected) { if (detail.is_protected) {
const dataKey = protected_session.getDataKey(req); const dataKey = protected_session.getDataKey(req);
@ -33,7 +33,7 @@ router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => {
}); });
router.post('/:parentNoteId/children', async (req, res, next) => { router.post('/:parentNoteId/children', async (req, res, next) => {
let parentNoteId = req.params.parentNoteId; const parentNoteId = req.params.parentNoteId;
const browserId = utils.browserId(req); const browserId = utils.browserId(req);
const note = req.body; const note = req.body;
@ -46,7 +46,7 @@ router.post('/:parentNoteId/children', async (req, res, next) => {
router.put('/:noteId', async (req, res, next) => { router.put('/:noteId', async (req, res, next) => {
const note = req.body; const note = req.body;
let noteId = req.params.noteId; const noteId = req.params.noteId;
const reqCtx = new RequestContext(req); const reqCtx = new RequestContext(req);
await notes.updateNote(noteId, note, reqCtx); await notes.updateNote(noteId, note, reqCtx);

View File

@ -9,6 +9,7 @@ const auth = require('../../services/auth');
const log = require('../../services/log'); const log = require('../../services/log');
const protected_session = require('../../services/protected_session'); const protected_session = require('../../services/protected_session');
const data_encryption = require('../../services/data_encryption'); const data_encryption = require('../../services/data_encryption');
const notes = require('../../services/notes');
router.get('/', auth.checkApiAuth, async (req, res, next) => { router.get('/', auth.checkApiAuth, async (req, res, next) => {
const notes = await sql.getResults("select " const notes = await sql.getResults("select "
@ -59,4 +60,16 @@ router.get('/', auth.checkApiAuth, async (req, res, next) => {
}); });
}); });
router.put('/:noteId/protectSubTree/:isProtected', auth.checkApiAuth, async (req, res, next) => {
const noteId = req.params.noteId;
const isProtected = !!parseInt(req.params.isProtected);
const dataKey = protected_session.getDataKey(req);
await sql.doInTransaction(async () => {
await notes.protectNoteRecursively(noteId, dataKey, isProtected);
});
res.send({});
});
module.exports = router; module.exports = router;

View File

@ -69,6 +69,70 @@ async function encryptNote(note, ctx) {
note.detail.note_text = data_encryption.encrypt(ctx.getDataKey(), note.detail.note_text); note.detail.note_text = data_encryption.encrypt(ctx.getDataKey(), note.detail.note_text);
} }
async function protectNoteRecursively(noteId, dataKey, protect) {
const note = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]);
await protectNote(note, dataKey, protect);
const children = await sql.getFlattenedResults("note_id", "SELECT note_id FROM notes_tree WHERE note_pid = ?", [noteId]);
for (const childNoteId of children) {
await protectNoteRecursively(childNoteId, dataKey, protect);
}
}
async function protectNote(note, dataKey, protect) {
let changed = false;
if (protect && !note.is_protected) {
note.note_title = data_encryption.encrypt(dataKey, note.note_title);
note.note_text = data_encryption.encrypt(dataKey, note.note_text);
note.is_protected = true;
changed = true;
}
else if (!protect && note.is_protected) {
note.note_title = data_encryption.decrypt(dataKey, note.note_title);
note.note_text = data_encryption.decrypt(dataKey, note.note_text);
note.is_protected = false;
changed = true;
}
if (changed) {
console.log("Updating...");
await sql.execute("UPDATE notes SET note_title = ?, note_text = ?, is_protected = ? WHERE note_id = ?",
[note.note_title, note.note_text, note.is_protected, note.note_id]);
await sql.addNoteSync(note.note_id);
}
await protectNoteHistory(note.note_id, dataKey, protect);
}
async function protectNoteHistory(noteId, dataKey, protect) {
const historyToChange = await sql.getResults("SELECT * FROM notes_history WHERE note_id = ? AND is_protected != ?", [noteId, protect]);
for (const history of historyToChange) {
if (protect) {
history.note_title = data_encryption.encrypt(dataKey, history.note_title);
history.note_text = data_encryption.encrypt(dataKey, history.note_text);
history.is_protected = true;
}
else {
history.note_title = data_encryption.decrypt(dataKey, history.note_title);
history.note_text = data_encryption.decrypt(dataKey, history.note_text);
history.is_protected = false;
}
await sql.execute("UPDATE notes_history SET note_title = ?, note_text = ?, is_protected = ? WHERE note_history_id = ?",
[history.note_title, history.note_text, history.is_protected, history.note_history_id]);
await sql.addNoteHistorySync(history.note_history_id);
}
}
async function updateNote(noteId, newNote, ctx) { async function updateNote(noteId, newNote, ctx) {
if (newNote.detail.is_protected) { if (newNote.detail.is_protected) {
await encryptNote(newNote, ctx); await encryptNote(newNote, ctx);
@ -109,23 +173,7 @@ async function updateNote(noteId, newNote, ctx) {
]); ]);
} }
const historyToChange = await sql.getResults("SELECT * FROM notes_history WHERE note_id = ? AND is_protected != ?", [noteId, newNote.detail.is_protected]); await protectNoteHistory(noteId, ctx.getDataKey(), newNote.detail.is_protected);
for (const history of historyToChange) {
if (newNote.detail.is_protected) {
history.note_title = data_encryption.encrypt(history.note_title);
history.note_text = data_encryption.encrypt(history.note_text);
history.is_protected = true;
}
else {
history.note_title = data_encryption.decrypt(history.note_title);
history.note_text = data_encryption.decrypt(history.note_text);
history.is_protected = false;
}
await sql.execute("UPDATE notes_history SET note_title = ?, note_text = ?, is_protected = ? WHERE note_history_id = ?",
[history.note_title, history.note_text, history.is_protected, history.note_history_id]);
}
await sql.addNoteHistorySync(noteHistoryId); await sql.addNoteHistorySync(noteHistoryId);
await addNoteAudits(origNoteDetail, newNote.detail, ctx.browserId); await addNoteAudits(origNoteDetail, newNote.detail, ctx.browserId);
@ -199,5 +247,6 @@ module.exports = {
createNewNote, createNewNote,
updateNote, updateNote,
addNoteAudits, addNoteAudits,
deleteNote deleteNote,
protectNoteRecursively
}; };