mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	server-ts: Port share/routes
This commit is contained in:
		
							parent
							
								
									88aba1c844
								
							
						
					
					
						commit
						c08393f04b
					
				
							
								
								
									
										26
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -92,6 +92,7 @@
 | 
				
			|||||||
        "@types/better-sqlite3": "^7.6.9",
 | 
					        "@types/better-sqlite3": "^7.6.9",
 | 
				
			||||||
        "@types/cls-hooked": "^4.3.8",
 | 
					        "@types/cls-hooked": "^4.3.8",
 | 
				
			||||||
        "@types/csurf": "^1.11.5",
 | 
					        "@types/csurf": "^1.11.5",
 | 
				
			||||||
 | 
					        "@types/ejs": "^3.1.5",
 | 
				
			||||||
        "@types/escape-html": "^1.0.4",
 | 
					        "@types/escape-html": "^1.0.4",
 | 
				
			||||||
        "@types/express": "^4.17.21",
 | 
					        "@types/express": "^4.17.21",
 | 
				
			||||||
        "@types/express-session": "^1.18.0",
 | 
					        "@types/express-session": "^1.18.0",
 | 
				
			||||||
@ -101,6 +102,7 @@
 | 
				
			|||||||
        "@types/mime-types": "^2.1.4",
 | 
					        "@types/mime-types": "^2.1.4",
 | 
				
			||||||
        "@types/multer": "^1.4.11",
 | 
					        "@types/multer": "^1.4.11",
 | 
				
			||||||
        "@types/node": "^20.11.19",
 | 
					        "@types/node": "^20.11.19",
 | 
				
			||||||
 | 
					        "@types/safe-compare": "^1.1.2",
 | 
				
			||||||
        "@types/sanitize-html": "^2.11.0",
 | 
					        "@types/sanitize-html": "^2.11.0",
 | 
				
			||||||
        "@types/sax": "^1.2.7",
 | 
					        "@types/sax": "^1.2.7",
 | 
				
			||||||
        "@types/stream-throttle": "^0.1.4",
 | 
					        "@types/stream-throttle": "^0.1.4",
 | 
				
			||||||
@ -1271,6 +1273,12 @@
 | 
				
			|||||||
        "@types/ms": "*"
 | 
					        "@types/ms": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@types/ejs": {
 | 
				
			||||||
 | 
					      "version": "3.1.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/escape-html": {
 | 
					    "node_modules/@types/escape-html": {
 | 
				
			||||||
      "version": "1.0.4",
 | 
					      "version": "1.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
 | 
				
			||||||
@ -1537,6 +1545,12 @@
 | 
				
			|||||||
        "@types/node": "*"
 | 
					        "@types/node": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@types/safe-compare": {
 | 
				
			||||||
 | 
					      "version": "1.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/safe-compare/-/safe-compare-1.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-kK/IM1+pvwCMom+Kezt/UlP8LMEwm8rP6UgGbRc6zUnhU/csoBQ5rWgmD2CJuHxiMiX+H1VqPGpo0kDluJGXYA==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/sanitize-html": {
 | 
					    "node_modules/@types/sanitize-html": {
 | 
				
			||||||
      "version": "2.11.0",
 | 
					      "version": "2.11.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
 | 
				
			||||||
@ -14276,6 +14290,12 @@
 | 
				
			|||||||
        "@types/ms": "*"
 | 
					        "@types/ms": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/ejs": {
 | 
				
			||||||
 | 
					      "version": "3.1.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-nv+GSx77ZtXiJzwKdsASqi+YQ5Z7vwHsTP0JY2SiQgjGckkBRKZnk8nIM+7oUZ1VCtuTz0+By4qVR7fqzp/Dfg==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/escape-html": {
 | 
					    "@types/escape-html": {
 | 
				
			||||||
      "version": "1.0.4",
 | 
					      "version": "1.0.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
 | 
				
			||||||
@ -14535,6 +14555,12 @@
 | 
				
			|||||||
        "@types/node": "*"
 | 
					        "@types/node": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "@types/safe-compare": {
 | 
				
			||||||
 | 
					      "version": "1.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/safe-compare/-/safe-compare-1.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-kK/IM1+pvwCMom+Kezt/UlP8LMEwm8rP6UgGbRc6zUnhU/csoBQ5rWgmD2CJuHxiMiX+H1VqPGpo0kDluJGXYA==",
 | 
				
			||||||
 | 
					      "dev": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "@types/sanitize-html": {
 | 
					    "@types/sanitize-html": {
 | 
				
			||||||
      "version": "2.11.0",
 | 
					      "version": "2.11.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.11.0.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -113,6 +113,7 @@
 | 
				
			|||||||
    "@types/better-sqlite3": "^7.6.9",
 | 
					    "@types/better-sqlite3": "^7.6.9",
 | 
				
			||||||
    "@types/cls-hooked": "^4.3.8",
 | 
					    "@types/cls-hooked": "^4.3.8",
 | 
				
			||||||
    "@types/csurf": "^1.11.5",
 | 
					    "@types/csurf": "^1.11.5",
 | 
				
			||||||
 | 
					    "@types/ejs": "^3.1.5",
 | 
				
			||||||
    "@types/escape-html": "^1.0.4",
 | 
					    "@types/escape-html": "^1.0.4",
 | 
				
			||||||
    "@types/express": "^4.17.21",
 | 
					    "@types/express": "^4.17.21",
 | 
				
			||||||
    "@types/express-session": "^1.18.0",
 | 
					    "@types/express-session": "^1.18.0",
 | 
				
			||||||
@ -122,6 +123,7 @@
 | 
				
			|||||||
    "@types/mime-types": "^2.1.4",
 | 
					    "@types/mime-types": "^2.1.4",
 | 
				
			||||||
    "@types/multer": "^1.4.11",
 | 
					    "@types/multer": "^1.4.11",
 | 
				
			||||||
    "@types/node": "^20.11.19",
 | 
					    "@types/node": "^20.11.19",
 | 
				
			||||||
 | 
					    "@types/safe-compare": "^1.1.2",
 | 
				
			||||||
    "@types/sanitize-html": "^2.11.0",
 | 
					    "@types/sanitize-html": "^2.11.0",
 | 
				
			||||||
    "@types/sax": "^1.2.7",
 | 
					    "@types/sax": "^1.2.7",
 | 
				
			||||||
    "@types/stream-throttle": "^0.1.4",
 | 
					    "@types/stream-throttle": "^0.1.4",
 | 
				
			||||||
 | 
				
			|||||||
@ -209,7 +209,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
 | 
				
			|||||||
            .map(childNote => this.becca.getBranchFromChildAndParent(childNote.noteId, this.noteId)) as BBranch[];
 | 
					            .map(childNote => this.becca.getBranchFromChildAndParent(childNote.noteId, this.noteId)) as BBranch[];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /**
 | 
				
			||||||
     * Note content has quite special handling - it's not a separate entity, but a lazily loaded
 | 
					     * Note content has quite special handling - it's not a separate entity, but a lazily loaded
 | 
				
			||||||
     * part of Note entity with its own sync. Reasons behind this hybrid design has been:
 | 
					     * part of Note entity with its own sync. Reasons behind this hybrid design has been:
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -222,7 +222,8 @@ class BNote extends AbstractBeccaEntity<BNote> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * @throws Error in case of invalid JSON */
 | 
					     * @throws Error in case of invalid JSON
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    getJsonContent(): any | null {
 | 
					    getJsonContent(): any | null {
 | 
				
			||||||
        const content = this.getContent();
 | 
					        const content = this.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -233,7 +234,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
 | 
				
			|||||||
        return JSON.parse(content);
 | 
					        return JSON.parse(content);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** @returns {*|null} valid object or null if the content cannot be parsed as JSON */
 | 
					    /** @returns valid object or null if the content cannot be parsed as JSON */
 | 
				
			||||||
    getJsonContentSafely() {
 | 
					    getJsonContentSafely() {
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            return this.getJsonContent();
 | 
					            return this.getJsonContent();
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,7 @@ const fontsRoute = require('./api/fonts');
 | 
				
			|||||||
const etapiTokensApiRoutes = require('./api/etapi_tokens');
 | 
					const etapiTokensApiRoutes = require('./api/etapi_tokens');
 | 
				
			||||||
const relationMapApiRoute = require('./api/relation-map');
 | 
					const relationMapApiRoute = require('./api/relation-map');
 | 
				
			||||||
const otherRoute = require('./api/other');
 | 
					const otherRoute = require('./api/other');
 | 
				
			||||||
const shareRoutes = require('../share/routes.js');
 | 
					const shareRoutes = require('../share/routes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const etapiAuthRoutes = require('../etapi/auth');
 | 
					const etapiAuthRoutes = require('../etapi/auth');
 | 
				
			||||||
const etapiAppInfoRoutes = require('../etapi/app_info');
 | 
					const etapiAppInfoRoutes = require('../etapi/app_info');
 | 
				
			||||||
 | 
				
			|||||||
@ -1,23 +1,24 @@
 | 
				
			|||||||
const express = require('express');
 | 
					import express = require('express');
 | 
				
			||||||
const path = require('path');
 | 
					import path = require('path');
 | 
				
			||||||
const safeCompare = require('safe-compare');
 | 
					import safeCompare = require('safe-compare');
 | 
				
			||||||
const ejs = require("ejs");
 | 
					import ejs = require("ejs");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const shaca = require('./shaca/shaca');
 | 
					import shaca = require('./shaca/shaca');
 | 
				
			||||||
const shacaLoader = require('./shaca/shaca_loader');
 | 
					import shacaLoader = require('./shaca/shaca_loader');
 | 
				
			||||||
const shareRoot = require('./share_root');
 | 
					import shareRoot = require('./share_root');
 | 
				
			||||||
const contentRenderer = require('./content_renderer');
 | 
					import contentRenderer = require('./content_renderer');
 | 
				
			||||||
const assetPath = require('../services/asset_path');
 | 
					import assetPath = require('../services/asset_path');
 | 
				
			||||||
const appPath = require('../services/app_path');
 | 
					import appPath = require('../services/app_path');
 | 
				
			||||||
const searchService = require('../services/search/services/search');
 | 
					import searchService = require('../services/search/services/search');
 | 
				
			||||||
const SearchContext = require('../services/search/search_context');
 | 
					import SearchContext = require('../services/search/search_context');
 | 
				
			||||||
const log = require('../services/log');
 | 
					import log = require('../services/log');
 | 
				
			||||||
 | 
					import SNote = require('./shaca/entities/snote');
 | 
				
			||||||
 | 
					import SBranch = require('./shaca/entities/sbranch');
 | 
				
			||||||
 | 
					import SAttachment = require('./shaca/entities/sattachment');
 | 
				
			||||||
 | 
					import BNote = require('../becca/entities/bnote');
 | 
				
			||||||
 | 
					import BRevision = require('../becca/entities/brevision');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } {
 | 
				
			||||||
 * @param {SNote} note
 | 
					 | 
				
			||||||
 * @return {{note: SNote, branch: SBranch}|{}}
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
function getSharedSubTreeRoot(note) {
 | 
					 | 
				
			||||||
    if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
 | 
					    if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
 | 
				
			||||||
        // share root itself is not shared
 | 
					        // share root itself is not shared
 | 
				
			||||||
        return {};
 | 
					        return {};
 | 
				
			||||||
@ -37,19 +38,18 @@ function getSharedSubTreeRoot(note) {
 | 
				
			|||||||
    return getSharedSubTreeRoot(parentBranch.getParentNote());
 | 
					    return getSharedSubTreeRoot(parentBranch.getParentNote());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function addNoIndexHeader(note, res) {
 | 
					function addNoIndexHeader(note: SNote, res: express.Response) {
 | 
				
			||||||
    if (note.isLabelTruthy('shareDisallowRobotIndexing')) {
 | 
					    if (note.isLabelTruthy('shareDisallowRobotIndexing')) {
 | 
				
			||||||
        res.setHeader('X-Robots-Tag', 'noindex');
 | 
					        res.setHeader('X-Robots-Tag', 'noindex');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function requestCredentials(res) {
 | 
					function requestCredentials(res: express.Response) {
 | 
				
			||||||
    res.setHeader('WWW-Authenticate', 'Basic realm="User Visible Realm", charset="UTF-8"')
 | 
					    res.setHeader('WWW-Authenticate', 'Basic realm="User Visible Realm", charset="UTF-8"')
 | 
				
			||||||
        .sendStatus(401);
 | 
					        .sendStatus(401);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @returns {SAttachment|boolean} */
 | 
					function checkAttachmentAccess(attachmentId: string, req: express.Request, res: express.Response) {
 | 
				
			||||||
function checkAttachmentAccess(attachmentId, req, res) {
 | 
					 | 
				
			||||||
    const attachment = shaca.getAttachment(attachmentId);
 | 
					    const attachment = shaca.getAttachment(attachmentId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!attachment) {
 | 
					    if (!attachment) {
 | 
				
			||||||
@ -65,8 +65,7 @@ function checkAttachmentAccess(attachmentId, req, res) {
 | 
				
			|||||||
    return note ? attachment : false;
 | 
					    return note ? attachment : false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @returns {SNote|boolean} */
 | 
					function checkNoteAccess(noteId: string, req: express.Request, res: express.Response) {
 | 
				
			||||||
function checkNoteAccess(noteId, req, res) {
 | 
					 | 
				
			||||||
    const note = shaca.getNote(noteId);
 | 
					    const note = shaca.getNote(noteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!note) {
 | 
					    if (!note) {
 | 
				
			||||||
@ -109,12 +108,16 @@ function checkNoteAccess(noteId, req, res) {
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function renderImageAttachment(image, res, attachmentName) {
 | 
					function renderImageAttachment(image: SNote, res: express.Response, attachmentName: string) {
 | 
				
			||||||
    let svgString = '<svg/>'
 | 
					    let svgString = '<svg/>'
 | 
				
			||||||
    const attachment = image.getAttachmentByTitle(attachmentName);
 | 
					    const attachment = image.getAttachmentByTitle(attachmentName);
 | 
				
			||||||
 | 
					    if (!attachment) {
 | 
				
			||||||
    if (attachment) {
 | 
					        res.status(404).render("share/404");
 | 
				
			||||||
        svgString = attachment.getContent();
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const content = attachment.getContent();
 | 
				
			||||||
 | 
					    if (typeof content === "string") {
 | 
				
			||||||
 | 
					        svgString = content;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        // backwards compatibility, before attachments, the SVG was stored in the main note content as a separate key
 | 
					        // backwards compatibility, before attachments, the SVG was stored in the main note content as a separate key
 | 
				
			||||||
        const contentSvg = image.getJsonContentSafely()?.svg;
 | 
					        const contentSvg = image.getJsonContentSafely()?.svg;
 | 
				
			||||||
@ -130,8 +133,8 @@ function renderImageAttachment(image, res, attachmentName) {
 | 
				
			|||||||
    res.send(svg);
 | 
					    res.send(svg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function register(router) {
 | 
					function register(router: express.Router) {
 | 
				
			||||||
    function renderNote(note, req, res) {
 | 
					    function renderNote(note: SNote, req: express.Request, res: express.Response) {
 | 
				
			||||||
        if (!note) {
 | 
					        if (!note) {
 | 
				
			||||||
            res.status(404).render("share/404");
 | 
					            res.status(404).render("share/404");
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -160,27 +163,34 @@ function register(router) {
 | 
				
			|||||||
        // Check if the user has their own template
 | 
					        // Check if the user has their own template
 | 
				
			||||||
        if (note.hasRelation('shareTemplate')) {
 | 
					        if (note.hasRelation('shareTemplate')) {
 | 
				
			||||||
            // Get the template note and content
 | 
					            // Get the template note and content
 | 
				
			||||||
            const templateId = note.getRelation('shareTemplate').value;
 | 
					            const templateId = note.getRelation('shareTemplate')?.value;
 | 
				
			||||||
            const templateNote = shaca.getNote(templateId);
 | 
					            const templateNote = templateId && shaca.getNote(templateId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Make sure the note type is correct
 | 
					            // Make sure the note type is correct
 | 
				
			||||||
            if (templateNote.type === 'code' && templateNote.mime === 'application/x-ejs') {
 | 
					            if (templateNote && templateNote.type === 'code' && templateNote.mime === 'application/x-ejs') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // EJS caches the result of this so we don't need to pre-cache
 | 
					                // EJS caches the result of this so we don't need to pre-cache
 | 
				
			||||||
                const includer = (path) => {
 | 
					                const includer = (path: string) => {
 | 
				
			||||||
                    const childNote = templateNote.children.find(n => path === n.title);
 | 
					                    const childNote = templateNote.children.find(n => path === n.title);
 | 
				
			||||||
                    if (!childNote) return null;
 | 
					                    if (!childNote) throw new Error("Unable to find child note.");
 | 
				
			||||||
                    if (childNote.type !== 'code' || childNote.mime !== 'application/x-ejs') return null;
 | 
					                    if (childNote.type !== 'code' || childNote.mime !== 'application/x-ejs') throw new Error("Incorrect child note type.");
 | 
				
			||||||
                    return { template: childNote.getContent() };
 | 
					
 | 
				
			||||||
 | 
					                    const template = childNote.getContent();
 | 
				
			||||||
 | 
					                    if (typeof template !== "string") throw new Error("Invalid template content type.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return { template };
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Try to render user's template, w/ fallback to default view
 | 
					                // Try to render user's template, w/ fallback to default view
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    const ejsResult = ejs.render(templateNote.getContent(), opts, { includer });
 | 
					                    const content = templateNote.getContent();
 | 
				
			||||||
                    res.send(ejsResult);
 | 
					                    if (typeof content === "string") {
 | 
				
			||||||
                    useDefaultView = false; // Rendering went okay, don't use default view
 | 
					                        const ejsResult = ejs.render(content, opts, { includer });
 | 
				
			||||||
 | 
					                        res.send(ejsResult);
 | 
				
			||||||
 | 
					                        useDefaultView = false; // Rendering went okay, don't use default view
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                catch (e) {
 | 
					                catch (e: any) {
 | 
				
			||||||
                    log.error(`Rendering user provided share template (${templateId}) threw exception ${e.message} with stacktrace: ${e.stack}`);
 | 
					                    log.error(`Rendering user provided share template (${templateId}) threw exception ${e.message} with stacktrace: ${e.stack}`);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -199,6 +209,11 @@ function register(router) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!shaca.shareRootNote) {
 | 
				
			||||||
 | 
					            return res.status(404)
 | 
				
			||||||
 | 
					                .json({ message: "Share root note not found" });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        renderNote(shaca.shareRootNote, req, res);
 | 
					        renderNote(shaca.shareRootNote, req, res);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -214,7 +229,7 @@ function register(router) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    router.get('/share/api/notes/:noteId', (req, res, next) => {
 | 
					    router.get('/share/api/notes/:noteId', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
        let note;
 | 
					        let note: SNote | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
					        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -228,7 +243,7 @@ function register(router) {
 | 
				
			|||||||
    router.get('/share/api/notes/:noteId/download', (req, res, next) => {
 | 
					    router.get('/share/api/notes/:noteId/download', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let note;
 | 
					        let note: SNote | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
					        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -252,7 +267,7 @@ function register(router) {
 | 
				
			|||||||
    router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
 | 
					    router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let image;
 | 
					        let image: SNote | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(image = checkNoteAccess(req.params.noteId, req, res))) {
 | 
					        if (!(image = checkNoteAccess(req.params.noteId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -277,7 +292,7 @@ function register(router) {
 | 
				
			|||||||
    router.get('/share/api/attachments/:attachmentId/image/:filename', (req, res, next) => {
 | 
					    router.get('/share/api/attachments/:attachmentId/image/:filename', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let attachment;
 | 
					        let attachment: SAttachment | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) {
 | 
					        if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -296,7 +311,7 @@ function register(router) {
 | 
				
			|||||||
    router.get('/share/api/attachments/:attachmentId/download', (req, res, next) => {
 | 
					    router.get('/share/api/attachments/:attachmentId/download', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let attachment;
 | 
					        let attachment: SAttachment | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) {
 | 
					        if (!(attachment = checkAttachmentAccess(req.params.attachmentId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -320,7 +335,7 @@ function register(router) {
 | 
				
			|||||||
    router.get('/share/api/notes/:noteId/view', (req, res, next) => {
 | 
					    router.get('/share/api/notes/:noteId/view', (req, res, next) => {
 | 
				
			||||||
        shacaLoader.ensureLoad();
 | 
					        shacaLoader.ensureLoad();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let note;
 | 
					        let note: SNote | boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
					        if (!(note = checkNoteAccess(req.params.noteId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -341,6 +356,10 @@ function register(router) {
 | 
				
			|||||||
        const ancestorNoteId = req.query.ancestorNoteId ?? "_share";
 | 
					        const ancestorNoteId = req.query.ancestorNoteId ?? "_share";
 | 
				
			||||||
        let note;
 | 
					        let note;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (typeof ancestorNoteId !== "string") {
 | 
				
			||||||
 | 
					            return res.status(400).json({ message: "'ancestorNoteId' parameter is mandatory." });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This will automatically return if no ancestorNoteId is provided and there is no shareIndex
 | 
					        // This will automatically return if no ancestorNoteId is provided and there is no shareIndex
 | 
				
			||||||
        if (!(note = checkNoteAccess(ancestorNoteId, req, res))) {
 | 
					        if (!(note = checkNoteAccess(ancestorNoteId, req, res))) {
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
@ -348,7 +367,7 @@ function register(router) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const { search } = req.query;
 | 
					        const { search } = req.query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!search?.trim()) {
 | 
					        if (typeof search !== "string" || !search?.trim()) {
 | 
				
			||||||
            return res.status(400).json({ message: "'search' parameter is mandatory." });
 | 
					            return res.status(400).json({ message: "'search' parameter is mandatory." });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -366,6 +385,6 @@ function register(router) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					export = {
 | 
				
			||||||
    register
 | 
					    register
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -8,10 +8,10 @@ import { Blob } from '../../../services/blob-interface';
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SAttachment extends AbstractShacaEntity {
 | 
					class SAttachment extends AbstractShacaEntity {
 | 
				
			||||||
    private attachmentId: string;
 | 
					    private attachmentId: string;
 | 
				
			||||||
    private ownerId: string;
 | 
					    ownerId: string;
 | 
				
			||||||
    title: string;
 | 
					    title: string;
 | 
				
			||||||
    role: string;
 | 
					    role: string;
 | 
				
			||||||
    private mime: string;
 | 
					    mime: string;
 | 
				
			||||||
    private blobId: string;
 | 
					    private blobId: string;
 | 
				
			||||||
    /** used for caching of images */
 | 
					    /** used for caching of images */
 | 
				
			||||||
    private utcDateModified: string;
 | 
					    private utcDateModified: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ class SBranch extends AbstractShacaEntity {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    private branchId: string;
 | 
					    private branchId: string;
 | 
				
			||||||
    private noteId: string;
 | 
					    private noteId: string;
 | 
				
			||||||
    private parentNoteId: string;
 | 
					    parentNoteId: string;
 | 
				
			||||||
    private prefix: string;
 | 
					    private prefix: string;
 | 
				
			||||||
    private isExpanded: boolean;
 | 
					    private isExpanded: boolean;
 | 
				
			||||||
    isHidden: boolean;
 | 
					    isHidden: boolean;
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ const isCredentials = (attr: SAttribute) => attr.type === 'label' && attr.name =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class SNote extends AbstractShacaEntity {
 | 
					class SNote extends AbstractShacaEntity {
 | 
				
			||||||
    noteId: string;
 | 
					    noteId: string;
 | 
				
			||||||
    private title: string;
 | 
					    title: string;
 | 
				
			||||||
    type: string;
 | 
					    type: string;
 | 
				
			||||||
    mime: string;
 | 
					    mime: string;
 | 
				
			||||||
    private blobId: string;
 | 
					    private blobId: string;
 | 
				
			||||||
@ -223,6 +223,29 @@ class SNote extends AbstractShacaEntity {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @throws Error in case of invalid JSON
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getJsonContent(): any | null {
 | 
				
			||||||
 | 
					        const content = this.getContent();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (typeof content !== "string" || !content || !content.trim()) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return JSON.parse(content);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @returns valid object or null if the content cannot be parsed as JSON */
 | 
				
			||||||
 | 
					    getJsonContentSafely() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            return this.getJsonContent();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        catch (e) {
 | 
				
			||||||
 | 
					            return null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hasAttribute(type: string, name: string) {
 | 
					    hasAttribute(type: string, name: string) {
 | 
				
			||||||
        return !!this.getAttributes().find(attr => attr.type === type && attr.name === name);
 | 
					        return !!this.getAttributes().find(attr => attr.type === type && attr.name === name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -10,10 +10,10 @@ export default class Shaca {
 | 
				
			|||||||
    childParentToBranch!: Record<string, SBranch>;
 | 
					    childParentToBranch!: Record<string, SBranch>;
 | 
				
			||||||
    private attributes!: Record<string, SAttribute>;
 | 
					    private attributes!: Record<string, SAttribute>;
 | 
				
			||||||
    attachments!: Record<string, SAttachment>;
 | 
					    attachments!: Record<string, SAttachment>;
 | 
				
			||||||
    private aliasToNote!: Record<string, SNote>;
 | 
					    aliasToNote!: Record<string, SNote>;
 | 
				
			||||||
    private shareRootNote!: SNote | null;
 | 
					    shareRootNote!: SNote | null;
 | 
				
			||||||
    /** true if the index of all shared subtrees is enabled */
 | 
					    /** true if the index of all shared subtrees is enabled */
 | 
				
			||||||
    private shareIndexEnabled!: boolean;
 | 
					    shareIndexEnabled!: boolean;
 | 
				
			||||||
    loaded!: boolean;
 | 
					    loaded!: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user