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: "Delete", cmd: "delete", uiIcon: "ui-icon-trash"},
{title: "----"},
{title: "Encrypt sub-tree", cmd: "encryptSubTree", uiIcon: "ui-icon-locked"},
{title: "Decrypt sub-tree", cmd: "decryptSubTree", uiIcon: "ui-icon-unlocked"},
{title: "Protect sub-tree", cmd: "protectSubTree", uiIcon: "ui-icon-locked"},
{title: "Unprotect sub-tree", cmd: "unprotectSubTree", uiIcon: "ui-icon-unlocked"},
{title: "----"},
{title: "Cut", cmd: "cut", uiIcon: "ui-icon-scissors"},
{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", "pasteInto", noteTree.getClipboardNoteId() !== null);
treeEl.contextmenu("enableEntry", "protectSubTree", protected_session.isProtectedSessionAvailable());
treeEl.contextmenu("enableEntry", "unprotectSubTree", protected_session.isProtectedSessionAvailable());
// Activate node on right-click
node.setActive();
// Disable tree keyboard handling
@ -64,11 +67,11 @@ const contextMenu = (function() {
else if (ui.cmd === "insertChildNote") {
noteEditor.createNote(node, node.key, 'into');
}
else if (ui.cmd === "encryptSubTree") {
protected_session.encryptSubTree(node.key);
else if (ui.cmd === "protectSubTree") {
protected_session.protectSubTree(node.key, true);
}
else if (ui.cmd === "decryptSubTree") {
protected_session.decryptSubTree(node.key);
else if (ui.cmd === "unprotectSubTree") {
protected_session.protectSubTree(node.key, false);
}
else if (ui.cmd === "cut") {
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(() => {
setupProtectedSession();
@ -167,6 +181,7 @@ const protected_session = (function() {
protectNoteAndSendToServer,
unprotectNoteAndSendToServer,
getProtectedSessionId,
touchProtectedSession
touchProtectedSession,
protectSubTree
};
})();

View File

@ -12,11 +12,11 @@ const data_encryption = require('../../services/data_encryption');
const RequestContext = require('../../services/request_context');
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);
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) {
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) => {
let parentNoteId = req.params.parentNoteId;
const parentNoteId = req.params.parentNoteId;
const browserId = utils.browserId(req);
const note = req.body;
@ -46,7 +46,7 @@ router.post('/:parentNoteId/children', async (req, res, next) => {
router.put('/:noteId', async (req, res, next) => {
const note = req.body;
let noteId = req.params.noteId;
const noteId = req.params.noteId;
const reqCtx = new RequestContext(req);
await notes.updateNote(noteId, note, reqCtx);

View File

@ -9,6 +9,7 @@ const auth = require('../../services/auth');
const log = require('../../services/log');
const protected_session = require('../../services/protected_session');
const data_encryption = require('../../services/data_encryption');
const notes = require('../../services/notes');
router.get('/', auth.checkApiAuth, async (req, res, next) => {
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;

View File

@ -69,6 +69,70 @@ async function encryptNote(note, ctx) {
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) {
if (newNote.detail.is_protected) {
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]);
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 protectNoteHistory(noteId, ctx.getDataKey(), newNote.detail.is_protected);
await sql.addNoteHistorySync(noteHistoryId);
await addNoteAudits(origNoteDetail, newNote.detail, ctx.browserId);
@ -199,5 +247,6 @@ module.exports = {
createNewNote,
updateNote,
addNoteAudits,
deleteNote
deleteNote,
protectNoteRecursively
};