mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/stable' into next
# Conflicts: # package-lock.json # package.json # src/public/app/entities/note_short.js # src/public/app/services/protected_session.js # src/routes/api/login.js
This commit is contained in:
		@@ -58,7 +58,7 @@
 | 
				
			|||||||
    "mime-types": "2.1.30",
 | 
					    "mime-types": "2.1.30",
 | 
				
			||||||
    "multer": "1.4.2",
 | 
					    "multer": "1.4.2",
 | 
				
			||||||
    "node-abi": "2.26.0",
 | 
					    "node-abi": "2.26.0",
 | 
				
			||||||
    "open": "8.0.6",
 | 
					    "open": "8.0.8",
 | 
				
			||||||
    "portscanner": "2.2.0",
 | 
					    "portscanner": "2.2.0",
 | 
				
			||||||
    "rand-token": "1.0.1",
 | 
					    "rand-token": "1.0.1",
 | 
				
			||||||
    "request": "^2.88.2",
 | 
					    "request": "^2.88.2",
 | 
				
			||||||
@@ -80,8 +80,8 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "cross-env": "7.0.3",
 | 
					    "cross-env": "7.0.3",
 | 
				
			||||||
    "electron": "13.0.0-beta.18",
 | 
					    "electron": "13.0.0-beta.23",
 | 
				
			||||||
    "electron-builder": "22.10.5",
 | 
					    "electron-builder": "22.11.1",
 | 
				
			||||||
    "electron-packager": "15.2.0",
 | 
					    "electron-packager": "15.2.0",
 | 
				
			||||||
    "electron-rebuild": "2.3.5",
 | 
					    "electron-rebuild": "2.3.5",
 | 
				
			||||||
    "esm": "3.2.25",
 | 
					    "esm": "3.2.25",
 | 
				
			||||||
@@ -90,7 +90,7 @@
 | 
				
			|||||||
    "lorem-ipsum": "2.0.3",
 | 
					    "lorem-ipsum": "2.0.3",
 | 
				
			||||||
    "rcedit": "3.0.0",
 | 
					    "rcedit": "3.0.0",
 | 
				
			||||||
    "webpack": "5.36.2",
 | 
					    "webpack": "5.36.2",
 | 
				
			||||||
    "webpack-cli": "4.6.0"
 | 
					    "webpack-cli": "4.7.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "optionalDependencies": {
 | 
					  "optionalDependencies": {
 | 
				
			||||||
    "electron-installer-debian": "3.1.0"
 | 
					    "electron-installer-debian": "3.1.0"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,8 @@ import noteAttributeCache from "../services/note_attribute_cache.js";
 | 
				
			|||||||
import ws from "../services/ws.js";
 | 
					import ws from "../services/ws.js";
 | 
				
			||||||
import options from "../services/options.js";
 | 
					import options from "../services/options.js";
 | 
				
			||||||
import froca from "../services/froca.js";
 | 
					import froca from "../services/froca.js";
 | 
				
			||||||
 | 
					import treeCache from "../services/tree_cache.js";
 | 
				
			||||||
 | 
					import bundle from "../services/bundle.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LABEL = 'label';
 | 
					const LABEL = 'label';
 | 
				
			||||||
const RELATION = 'relation';
 | 
					const RELATION = 'relation';
 | 
				
			||||||
@@ -701,6 +703,55 @@ class NoteShort {
 | 
				
			|||||||
        const labels = this.getLabels('workspaceTabBackgroundColor');
 | 
					        const labels = this.getLabels('workspaceTabBackgroundColor');
 | 
				
			||||||
        return labels.length > 0 ? labels[0].value : "";
 | 
					        return labels.length > 0 ? labels[0].value : "";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @returns {boolean} true if this note is JavaScript (code or attachment) */
 | 
				
			||||||
 | 
					    isJavaScript() {
 | 
				
			||||||
 | 
					        return (this.type === "code" || this.type === "file")
 | 
				
			||||||
 | 
					            && (this.mime.startsWith("application/javascript")
 | 
				
			||||||
 | 
					                || this.mime === "application/x-javascript"
 | 
				
			||||||
 | 
					                || this.mime === "text/javascript");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @returns {boolean} true if this note is HTML */
 | 
				
			||||||
 | 
					    isHtml() {
 | 
				
			||||||
 | 
					        return (this.type === "code" || this.type === "file" || this.type === "render") && this.mime === "text/html";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @returns {string|null} JS script environment - either "frontend" or "backend" */
 | 
				
			||||||
 | 
					    getScriptEnv() {
 | 
				
			||||||
 | 
					        if (this.isHtml() || (this.isJavaScript() && this.mime.endsWith('env=frontend'))) {
 | 
				
			||||||
 | 
					            return "frontend";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.type === 'render') {
 | 
				
			||||||
 | 
					            return "frontend";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.isJavaScript() && this.mime.endsWith('env=backend')) {
 | 
				
			||||||
 | 
					            return "backend";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async executeScript() {
 | 
				
			||||||
 | 
					        if (!this.isJavaScript()) {
 | 
				
			||||||
 | 
					            throw new Error(`Note ${this.noteId} is of type ${this.type} and mime ${this.mime} and thus cannot be executed`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const env = this.getScriptEnv();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (env === "frontend") {
 | 
				
			||||||
 | 
					            const bundleService = (await import("../services/bundle.js")).default;
 | 
				
			||||||
 | 
					            await bundleService.getAndExecuteBundle(this.noteId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (env === "backend") {
 | 
				
			||||||
 | 
					            await server.post('script/run/' + this.noteId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            throw new Error(`Unrecognized env type ${env} for note ${this.noteId}`);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default NoteShort;
 | 
					export default NoteShort;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,8 +119,6 @@ const appContext = new AppContext(window.glob.isMainWindow);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// we should save all outstanding changes before the page/app is closed
 | 
					// we should save all outstanding changes before the page/app is closed
 | 
				
			||||||
$(window).on('beforeunload', () => {
 | 
					$(window).on('beforeunload', () => {
 | 
				
			||||||
    protectedSessionHolder.resetSessionCookie();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let allSaved = true;
 | 
					    let allSaved = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter(wr => !!wr.deref());
 | 
					    appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter(wr => !!wr.deref());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -216,6 +216,7 @@ export default class Entrypoints extends Component {
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO: use note.executeScript()
 | 
				
			||||||
        if (note.mime.endsWith("env=frontend")) {
 | 
					        if (note.mime.endsWith("env=frontend")) {
 | 
				
			||||||
            await bundleService.getAndExecuteBundle(note.noteId);
 | 
					            await bundleService.getAndExecuteBundle(note.noteId);
 | 
				
			||||||
        } else if (note.mime.endsWith("env=backend")) {
 | 
					        } else if (note.mime.endsWith("env=backend")) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,8 +68,6 @@ function setupGlobs() {
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protectedSessionHolder.setProtectedSessionId(null);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (const appCssNoteId of glob.appCssNoteIds || []) {
 | 
					    for (const appCssNoteId of glob.appCssNoteIds || []) {
 | 
				
			||||||
        libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`);
 | 
					        libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,16 +1,16 @@
 | 
				
			|||||||
import utils from './utils.js';
 | 
					 | 
				
			||||||
import server from './server.js';
 | 
					import server from './server.js';
 | 
				
			||||||
import protectedSessionHolder from './protected_session_holder.js';
 | 
					import protectedSessionHolder from './protected_session_holder.js';
 | 
				
			||||||
import toastService from "./toast.js";
 | 
					import toastService from "./toast.js";
 | 
				
			||||||
import ws from "./ws.js";
 | 
					import ws from "./ws.js";
 | 
				
			||||||
import appContext from "./app_context.js";
 | 
					import appContext from "./app_context.js";
 | 
				
			||||||
import froca from "./froca.js";
 | 
					import froca from "./froca.js";
 | 
				
			||||||
 | 
					import utils from "./utils.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let protectedSessionDeferred = null;
 | 
					let protectedSessionDeferred = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function leaveProtectedSession() {
 | 
					async function leaveProtectedSession() {
 | 
				
			||||||
    if (protectedSessionHolder.isProtectedSessionAvailable()) {
 | 
					    if (protectedSessionHolder.isProtectedSessionAvailable()) {
 | 
				
			||||||
        protectedSessionHolder.resetProtectedSession();
 | 
					        await protectedSessionHolder.resetProtectedSession();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,16 +41,18 @@ async function reloadData() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function setupProtectedSession(password) {
 | 
					async function setupProtectedSession(password) {
 | 
				
			||||||
    const response = await enterProtectedSessionOnServer(password);
 | 
					    const response = await server.post('login/protected', { password: password });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!response.success) {
 | 
					    if (!response.success) {
 | 
				
			||||||
        toastService.showError("Wrong password.", 3000);
 | 
					        toastService.showError("Wrong password.", 3000);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protectedSessionHolder.setProtectedSessionId(response.protectedSessionId);
 | 
					    protectedSessionHolder.enableProtectedSession();
 | 
				
			||||||
    protectedSessionHolder.touchProtectedSession();
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ws.subscribeToMessages(async message => {
 | 
				
			||||||
 | 
					    if (message.type === 'protectedSessionLogin') {
 | 
				
			||||||
        await reloadData();
 | 
					        await reloadData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await appContext.triggerEvent('frocaReloaded');
 | 
					    await appContext.triggerEvent('frocaReloaded');
 | 
				
			||||||
@@ -66,12 +68,10 @@ async function setupProtectedSession(password) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        toastService.showMessage("Protected session has been started.");
 | 
					        toastService.showMessage("Protected session has been started.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    else if (message.type === 'protectedSessionLogout') {
 | 
				
			||||||
async function enterProtectedSessionOnServer(password) {
 | 
					        utils.reloadApp();
 | 
				
			||||||
    return await server.post('login/protected', {
 | 
					 | 
				
			||||||
        password: password
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function protectNote(noteId, protect, includingSubtree) {
 | 
					async function protectNote(noteId, protect, includingSubtree) {
 | 
				
			||||||
    await enterProtectedSession();
 | 
					    await enterProtectedSession();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,6 @@
 | 
				
			|||||||
import utils from "./utils.js";
 | 
					 | 
				
			||||||
import options from './options.js';
 | 
					import options from './options.js';
 | 
				
			||||||
import server from "./server.js";
 | 
					import server from "./server.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PROTECTED_SESSION_ID_KEY = 'protectedSessionId';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let lastProtectedSessionOperationDate = 0;
 | 
					let lastProtectedSessionOperationDate = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
setInterval(() => {
 | 
					setInterval(() => {
 | 
				
			||||||
@@ -15,32 +12,23 @@ setInterval(() => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}, 10000);
 | 
					}, 10000);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function setProtectedSessionId(id) {
 | 
					function enableProtectedSession() {
 | 
				
			||||||
    // using session cookie so that it disappears after browser/tab is closed
 | 
					    glob.isProtectedSessionAvailable = true;
 | 
				
			||||||
    utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
function resetSessionCookie() {
 | 
					    touchProtectedSession();
 | 
				
			||||||
    utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, null);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function resetProtectedSession() {
 | 
					async function resetProtectedSession() {
 | 
				
			||||||
    resetSessionCookie();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    await server.post("logout/protected");
 | 
					    await server.post("logout/protected");
 | 
				
			||||||
 | 
					 | 
				
			||||||
    utils.reloadApp();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function isProtectedSessionAvailable() {
 | 
					function isProtectedSessionAvailable() {
 | 
				
			||||||
    return !!utils.getCookie(PROTECTED_SESSION_ID_KEY);
 | 
					    return glob.isProtectedSessionAvailable;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function touchProtectedSession() {
 | 
					function touchProtectedSession() {
 | 
				
			||||||
    if (isProtectedSessionAvailable()) {
 | 
					    if (isProtectedSessionAvailable()) {
 | 
				
			||||||
        lastProtectedSessionOperationDate = Date.now();
 | 
					        lastProtectedSessionOperationDate = Date.now();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        setProtectedSessionId(utils.getCookie(PROTECTED_SESSION_ID_KEY));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,8 +39,7 @@ function touchProtectedSessionIfNecessary(note) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
    setProtectedSessionId,
 | 
					    enableProtectedSession,
 | 
				
			||||||
    resetSessionCookie,
 | 
					 | 
				
			||||||
    resetProtectedSession,
 | 
					    resetProtectedSession,
 | 
				
			||||||
    isProtectedSessionAvailable,
 | 
					    isProtectedSessionAvailable,
 | 
				
			||||||
    touchProtectedSession,
 | 
					    touchProtectedSession,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
import BasicWidget from "./basic_widget.js";
 | 
					import BasicWidget from "./basic_widget.js";
 | 
				
			||||||
import HistoryNavigationWidget from "./history_navigation.js";
 | 
					import HistoryNavigationWidget from "./history_navigation.js";
 | 
				
			||||||
 | 
					import protectedSessionHolder from "../services/protected_session_holder.js";
 | 
				
			||||||
import protectedSessionService from "../services/protected_session.js";
 | 
					import protectedSessionService from "../services/protected_session.js";
 | 
				
			||||||
import QuickSearchWidget from "./quick_search.js";
 | 
					import QuickSearchWidget from "./quick_search.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -68,8 +69,7 @@ const TPL = `
 | 
				
			|||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
        <button class="btn btn-sm leave-protected-session-button noborder"
 | 
					        <button class="btn btn-sm leave-protected-session-button noborder"
 | 
				
			||||||
                title="Leave protected session so that protected notes are not accessible any more."
 | 
					                title="Leave protected session so that protected notes are not accessible any more.">
 | 
				
			||||||
                style="display: none;">
 | 
					 | 
				
			||||||
            <span class="bx bx-log-out"></span>
 | 
					            <span class="bx bx-log-out"></span>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
            Leave protected session
 | 
					            Leave protected session
 | 
				
			||||||
@@ -96,9 +96,11 @@ export default class StandardTopWidget extends BasicWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.$enterProtectedSessionButton = this.$widget.find(".enter-protected-session-button");
 | 
					        this.$enterProtectedSessionButton = this.$widget.find(".enter-protected-session-button");
 | 
				
			||||||
        this.$enterProtectedSessionButton.on('click', protectedSessionService.enterProtectedSession);
 | 
					        this.$enterProtectedSessionButton.on('click', protectedSessionService.enterProtectedSession);
 | 
				
			||||||
 | 
					        this.$enterProtectedSessionButton.toggle(!protectedSessionHolder.isProtectedSessionAvailable());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.$leaveProtectedSessionButton = this.$widget.find(".leave-protected-session-button");
 | 
					        this.$leaveProtectedSessionButton = this.$widget.find(".leave-protected-session-button");
 | 
				
			||||||
        this.$leaveProtectedSessionButton.on('click', protectedSessionService.leaveProtectedSession);
 | 
					        this.$leaveProtectedSessionButton.on('click', protectedSessionService.leaveProtectedSession);
 | 
				
			||||||
 | 
					        this.$leaveProtectedSessionButton.toggle(protectedSessionHolder.isProtectedSessionAvailable());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.$widget;
 | 
					        return this.$widget;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,6 +14,10 @@ button.btn, button.btn-sm {
 | 
				
			|||||||
    font-size: inherit;
 | 
					    font-size: inherit;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-micro {
 | 
				
			||||||
 | 
					    padding: 0 10px 0 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.input-group-text {
 | 
					.input-group-text {
 | 
				
			||||||
    background-color: var(--accented-background-color) !important;
 | 
					    background-color: var(--accented-background-color) !important;
 | 
				
			||||||
    color: var(--muted-text-color) !important;
 | 
					    color: var(--muted-text-color) !important;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,11 +8,12 @@ const passwordEncryptionService = require('../../services/password_encryption');
 | 
				
			|||||||
const protectedSessionService = require('../../services/protected_session');
 | 
					const protectedSessionService = require('../../services/protected_session');
 | 
				
			||||||
const appInfo = require('../../services/app_info');
 | 
					const appInfo = require('../../services/app_info');
 | 
				
			||||||
const eventService = require('../../services/events');
 | 
					const eventService = require('../../services/events');
 | 
				
			||||||
const cls = require('../../services/cls');
 | 
					 | 
				
			||||||
const sqlInit = require('../../services/sql_init');
 | 
					const sqlInit = require('../../services/sql_init');
 | 
				
			||||||
const sql = require('../../services/sql');
 | 
					const sql = require('../../services/sql');
 | 
				
			||||||
const optionService = require('../../services/options');
 | 
					const optionService = require('../../services/options');
 | 
				
			||||||
const ApiToken = require('../../services/becca/entities/api_token.js');
 | 
					const ApiToken = require('../../services/becca/entities/api_token.js');
 | 
				
			||||||
 | 
					const ApiToken = require('../../entities/api_token');
 | 
				
			||||||
 | 
					const ws = require("../../services/ws.js");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function loginSync(req) {
 | 
					function loginSync(req) {
 | 
				
			||||||
    if (!sqlInit.schemaExists()) {
 | 
					    if (!sqlInit.schemaExists()) {
 | 
				
			||||||
@@ -65,16 +66,14 @@ function loginToProtectedSession(req) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const decryptedDataKey = passwordEncryptionService.getDataKey(password);
 | 
					    const decryptedDataKey = passwordEncryptionService.getDataKey(password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const protectedSessionId = protectedSessionService.setDataKey(decryptedDataKey);
 | 
					    protectedSessionService.setDataKey(decryptedDataKey);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // this is set here so that event handlers have access to the protected session
 | 
					 | 
				
			||||||
    cls.set('protectedSessionId', protectedSessionId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eventService.emit(eventService.ENTER_PROTECTED_SESSION);
 | 
					    eventService.emit(eventService.ENTER_PROTECTED_SESSION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ws.sendMessageToAllClients({ type: 'protectedSessionLogin' });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        success: true,
 | 
					        success: true
 | 
				
			||||||
        protectedSessionId: protectedSessionId
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,6 +81,8 @@ function logoutFromProtectedSession() {
 | 
				
			|||||||
    protectedSessionService.resetDataKey();
 | 
					    protectedSessionService.resetDataKey();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eventService.emit(eventService.LEAVE_PROTECTED_SESSION);
 | 
					    eventService.emit(eventService.LEAVE_PROTECTED_SESSION);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ws.sendMessageToAllClients({ type: 'protectedSessionLogout' });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function token(req) {
 | 
					function token(req) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,6 +7,7 @@ const config = require('../services/config');
 | 
				
			|||||||
const optionService = require('../services/options');
 | 
					const optionService = require('../services/options');
 | 
				
			||||||
const log = require('../services/log');
 | 
					const log = require('../services/log');
 | 
				
			||||||
const env = require('../services/env');
 | 
					const env = require('../services/env');
 | 
				
			||||||
 | 
					const protectedSessionService = require("../services/protected_session.js");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function index(req, res) {
 | 
					function index(req, res) {
 | 
				
			||||||
    const options = optionService.getOptionsMap();
 | 
					    const options = optionService.getOptionsMap();
 | 
				
			||||||
@@ -30,7 +31,8 @@ function index(req, res) {
 | 
				
			|||||||
        appCssNoteIds: getAppCssNoteIds(),
 | 
					        appCssNoteIds: getAppCssNoteIds(),
 | 
				
			||||||
        isDev: env.isDev(),
 | 
					        isDev: env.isDev(),
 | 
				
			||||||
        isMainWindow: !req.query.extra,
 | 
					        isMainWindow: !req.query.extra,
 | 
				
			||||||
        extraHoistedNoteId: req.query.extraHoistedNoteId
 | 
					        extraHoistedNoteId: req.query.extraHoistedNoteId,
 | 
				
			||||||
 | 
					        isProtectedSessionAvailable: protectedSessionService.isProtectedSessionAvailable()
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -93,7 +93,6 @@ function route(method, path, middleware, routeHandler, resultHandler, transactio
 | 
				
			|||||||
                cls.set('sourceId', req.headers['trilium-source-id']);
 | 
					                cls.set('sourceId', req.headers['trilium-source-id']);
 | 
				
			||||||
                cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']);
 | 
					                cls.set('localNowDateTime', req.headers['trilium-local-now-datetime']);
 | 
				
			||||||
                cls.set('hoistedNoteId', req.headers['trilium-hoisted-note-id'] || 'root');
 | 
					                cls.set('hoistedNoteId', req.headers['trilium-hoisted-note-id'] || 'root');
 | 
				
			||||||
                protectedSessionService.setProtectedSessionId(req);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const cb = () => routeHandler(req, res, next);
 | 
					                const cb = () => routeHandler(req, res, next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,42 +1,24 @@
 | 
				
			|||||||
"use strict";
 | 
					"use strict";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const utils = require('./utils');
 | 
					 | 
				
			||||||
const log = require('./log');
 | 
					const log = require('./log');
 | 
				
			||||||
const dataEncryptionService = require('./data_encryption');
 | 
					const dataEncryptionService = require('./data_encryption');
 | 
				
			||||||
const cls = require('./cls');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let dataKeyMap = {};
 | 
					let dataKey = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function setDataKey(decryptedDataKey) {
 | 
					function setDataKey(decryptedDataKey) {
 | 
				
			||||||
    const protectedSessionId = utils.randomSecureToken(32);
 | 
					    dataKey = Array.from(decryptedDataKey);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    dataKeyMap[protectedSessionId] = Array.from(decryptedDataKey); // can't store buffer in session
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return protectedSessionId;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function setProtectedSessionId(req) {
 | 
					 | 
				
			||||||
    cls.set('protectedSessionId', req.cookies.protectedSessionId);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function getProtectedSessionId() {
 | 
					 | 
				
			||||||
    return cls.get('protectedSessionId');
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getDataKey() {
 | 
					function getDataKey() {
 | 
				
			||||||
    const protectedSessionId = getProtectedSessionId();
 | 
					    return dataKey;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return dataKeyMap[protectedSessionId];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function resetDataKey() {
 | 
					function resetDataKey() {
 | 
				
			||||||
    dataKeyMap = {};
 | 
					    dataKey = null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function isProtectedSessionAvailable() {
 | 
					function isProtectedSessionAvailable() {
 | 
				
			||||||
    const protectedSessionId = getProtectedSessionId();
 | 
					    return !!dataKey;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return !!dataKeyMap[protectedSessionId];
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function decryptNotes(notes) {
 | 
					function decryptNotes(notes) {
 | 
				
			||||||
@@ -74,12 +56,10 @@ function decryptString(cipherText) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
    setDataKey,
 | 
					    setDataKey,
 | 
				
			||||||
    getDataKey,
 | 
					 | 
				
			||||||
    resetDataKey,
 | 
					    resetDataKey,
 | 
				
			||||||
    isProtectedSessionAvailable,
 | 
					    isProtectedSessionAvailable,
 | 
				
			||||||
    encrypt,
 | 
					    encrypt,
 | 
				
			||||||
    decrypt,
 | 
					    decrypt,
 | 
				
			||||||
    decryptString,
 | 
					    decryptString,
 | 
				
			||||||
    decryptNotes,
 | 
					    decryptNotes
 | 
				
			||||||
    setProtectedSessionId
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@
 | 
				
			|||||||
        appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>,
 | 
					        appCssNoteIds: <%- JSON.stringify(appCssNoteIds) %>,
 | 
				
			||||||
        isMainWindow: <%= isMainWindow %>,
 | 
					        isMainWindow: <%= isMainWindow %>,
 | 
				
			||||||
        extraHoistedNoteId: '<%= extraHoistedNoteId %>',
 | 
					        extraHoistedNoteId: '<%= extraHoistedNoteId %>',
 | 
				
			||||||
 | 
					        isProtectedSessionAvailable: <%= isProtectedSessionAvailable %>,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user