diff --git a/package.json b/package.json index b00643cf5..5a616df81 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "mime-types": "2.1.30", "multer": "1.4.2", "node-abi": "2.26.0", - "open": "8.0.6", + "open": "8.0.8", "portscanner": "2.2.0", "rand-token": "1.0.1", "request": "^2.88.2", @@ -80,8 +80,8 @@ }, "devDependencies": { "cross-env": "7.0.3", - "electron": "13.0.0-beta.18", - "electron-builder": "22.10.5", + "electron": "13.0.0-beta.23", + "electron-builder": "22.11.1", "electron-packager": "15.2.0", "electron-rebuild": "2.3.5", "esm": "3.2.25", @@ -90,7 +90,7 @@ "lorem-ipsum": "2.0.3", "rcedit": "3.0.0", "webpack": "5.36.2", - "webpack-cli": "4.6.0" + "webpack-cli": "4.7.0" }, "optionalDependencies": { "electron-installer-debian": "3.1.0" diff --git a/src/public/app/entities/note_short.js b/src/public/app/entities/note_short.js index 370b5eaa9..92298f46b 100644 --- a/src/public/app/entities/note_short.js +++ b/src/public/app/entities/note_short.js @@ -3,6 +3,8 @@ import noteAttributeCache from "../services/note_attribute_cache.js"; import ws from "../services/ws.js"; import options from "../services/options.js"; import froca from "../services/froca.js"; +import treeCache from "../services/tree_cache.js"; +import bundle from "../services/bundle.js"; const LABEL = 'label'; const RELATION = 'relation'; @@ -701,6 +703,55 @@ class NoteShort { const labels = this.getLabels('workspaceTabBackgroundColor'); 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; diff --git a/src/public/app/services/app_context.js b/src/public/app/services/app_context.js index 56ada9cf7..220dfc866 100644 --- a/src/public/app/services/app_context.js +++ b/src/public/app/services/app_context.js @@ -119,8 +119,6 @@ const appContext = new AppContext(window.glob.isMainWindow); // we should save all outstanding changes before the page/app is closed $(window).on('beforeunload', () => { - protectedSessionHolder.resetSessionCookie(); - let allSaved = true; appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter(wr => !!wr.deref()); diff --git a/src/public/app/services/entrypoints.js b/src/public/app/services/entrypoints.js index f8d56658b..08f4747c8 100644 --- a/src/public/app/services/entrypoints.js +++ b/src/public/app/services/entrypoints.js @@ -216,6 +216,7 @@ export default class Entrypoints extends Component { return; } + // TODO: use note.executeScript() if (note.mime.endsWith("env=frontend")) { await bundleService.getAndExecuteBundle(note.noteId); } else if (note.mime.endsWith("env=backend")) { diff --git a/src/public/app/services/glob.js b/src/public/app/services/glob.js index 8e8c5e750..f91a48148 100644 --- a/src/public/app/services/glob.js +++ b/src/public/app/services/glob.js @@ -68,8 +68,6 @@ function setupGlobs() { return false; }; - protectedSessionHolder.setProtectedSessionId(null); - for (const appCssNoteId of glob.appCssNoteIds || []) { libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`); } diff --git a/src/public/app/services/protected_session.js b/src/public/app/services/protected_session.js index ffbd72031..57f811679 100644 --- a/src/public/app/services/protected_session.js +++ b/src/public/app/services/protected_session.js @@ -1,16 +1,16 @@ -import utils from './utils.js'; import server from './server.js'; import protectedSessionHolder from './protected_session_holder.js'; import toastService from "./toast.js"; import ws from "./ws.js"; import appContext from "./app_context.js"; import froca from "./froca.js"; +import utils from "./utils.js"; let protectedSessionDeferred = null; async function leaveProtectedSession() { if (protectedSessionHolder.isProtectedSessionAvailable()) { - protectedSessionHolder.resetProtectedSession(); + await protectedSessionHolder.resetProtectedSession(); } } @@ -41,37 +41,37 @@ async function reloadData() { } async function setupProtectedSession(password) { - const response = await enterProtectedSessionOnServer(password); + const response = await server.post('login/protected', { password: password }); if (!response.success) { toastService.showError("Wrong password.", 3000); return; } - protectedSessionHolder.setProtectedSessionId(response.protectedSessionId); - protectedSessionHolder.touchProtectedSession(); + protectedSessionHolder.enableProtectedSession(); +} - await reloadData(); +ws.subscribeToMessages(async message => { + if (message.type === 'protectedSessionLogin') { + await reloadData(); await appContext.triggerEvent('frocaReloaded'); - appContext.triggerEvent('protectedSessionStarted'); + appContext.triggerEvent('protectedSessionStarted'); - if (protectedSessionDeferred !== null) { - import("../dialogs/protected_session.js").then(dialog => dialog.close()); + if (protectedSessionDeferred !== null) { + import("../dialogs/protected_session.js").then(dialog => dialog.close()); - protectedSessionDeferred.resolve(true); - protectedSessionDeferred = null; + protectedSessionDeferred.resolve(true); + protectedSessionDeferred = null; + } + + toastService.showMessage("Protected session has been started."); } - - toastService.showMessage("Protected session has been started."); -} - -async function enterProtectedSessionOnServer(password) { - return await server.post('login/protected', { - password: password - }); -} + else if (message.type === 'protectedSessionLogout') { + utils.reloadApp(); + } +}); async function protectNote(noteId, protect, includingSubtree) { await enterProtectedSession(); diff --git a/src/public/app/services/protected_session_holder.js b/src/public/app/services/protected_session_holder.js index be2dfc500..86ff20b2b 100644 --- a/src/public/app/services/protected_session_holder.js +++ b/src/public/app/services/protected_session_holder.js @@ -1,9 +1,6 @@ -import utils from "./utils.js"; import options from './options.js'; import server from "./server.js"; -const PROTECTED_SESSION_ID_KEY = 'protectedSessionId'; - let lastProtectedSessionOperationDate = 0; setInterval(() => { @@ -15,32 +12,23 @@ setInterval(() => { } }, 10000); -function setProtectedSessionId(id) { - // using session cookie so that it disappears after browser/tab is closed - utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, id); -} +function enableProtectedSession() { + glob.isProtectedSessionAvailable = true; -function resetSessionCookie() { - utils.setSessionCookie(PROTECTED_SESSION_ID_KEY, null); + touchProtectedSession(); } async function resetProtectedSession() { - resetSessionCookie(); - await server.post("logout/protected"); - - utils.reloadApp(); } function isProtectedSessionAvailable() { - return !!utils.getCookie(PROTECTED_SESSION_ID_KEY); + return glob.isProtectedSessionAvailable; } function touchProtectedSession() { if (isProtectedSessionAvailable()) { lastProtectedSessionOperationDate = Date.now(); - - setProtectedSessionId(utils.getCookie(PROTECTED_SESSION_ID_KEY)); } } @@ -51,8 +39,7 @@ function touchProtectedSessionIfNecessary(note) { } export default { - setProtectedSessionId, - resetSessionCookie, + enableProtectedSession, resetProtectedSession, isProtectedSessionAvailable, touchProtectedSession, diff --git a/src/public/app/widgets/standard_top_widget.js b/src/public/app/widgets/standard_top_widget.js index 0b14723f6..5e346ef9c 100644 --- a/src/public/app/widgets/standard_top_widget.js +++ b/src/public/app/widgets/standard_top_widget.js @@ -1,5 +1,6 @@ import BasicWidget from "./basic_widget.js"; import HistoryNavigationWidget from "./history_navigation.js"; +import protectedSessionHolder from "../services/protected_session_holder.js"; import protectedSessionService from "../services/protected_session.js"; import QuickSearchWidget from "./quick_search.js"; @@ -68,8 +69,7 @@ const TPL = `