mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
protect/unprotect subtree
This commit is contained in:
parent
c2ad14ba18
commit
9cf935efd1
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
})();
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user