mirror of
https://github.com/zadam/trilium.git
synced 2026-04-11 22:47:46 +02:00
Merge remote-tracking branch 'origin/main' into standalone
This commit is contained in:
@@ -10,6 +10,7 @@ import helmet from "helmet";
|
||||
import { t } from "i18next";
|
||||
import path from "path";
|
||||
import favicon from "serve-favicon";
|
||||
import type serveStatic from "serve-static";
|
||||
|
||||
import assets from "./routes/assets.js";
|
||||
import custom from "./routes/custom.js";
|
||||
@@ -22,6 +23,9 @@ import openID from "./services/open_id.js";
|
||||
import { RESOURCE_DIR } from "./services/resource_dir.js";
|
||||
import utils, { getResourceDir, isDev } from "./services/utils.js";
|
||||
|
||||
// Allow serving assets even if the installation path contains a hidden (dot-prefixed) directory.
|
||||
const STATIC_OPTIONS: serveStatic.ServeStaticOptions = { dotfiles: "allow" };
|
||||
|
||||
export default async function buildApp() {
|
||||
const app = express();
|
||||
|
||||
@@ -97,10 +101,10 @@ export default async function buildApp() {
|
||||
// localhost-only guard and does not require Trilium authentication.
|
||||
mcpRoutes.register(app);
|
||||
|
||||
app.use(express.static(path.join(publicDir, "root")));
|
||||
app.use(`/manifest.webmanifest`, express.static(path.join(publicAssetsDir, "manifest.webmanifest")));
|
||||
app.use(`/robots.txt`, express.static(path.join(publicAssetsDir, "robots.txt")));
|
||||
app.use(`/icon.png`, express.static(path.join(publicAssetsDir, "icon.png")));
|
||||
app.use(express.static(path.join(publicDir, "root"), STATIC_OPTIONS));
|
||||
app.use(`/manifest.webmanifest`, express.static(path.join(publicAssetsDir, "manifest.webmanifest"), STATIC_OPTIONS));
|
||||
app.use(`/robots.txt`, express.static(path.join(publicAssetsDir, "robots.txt"), STATIC_OPTIONS));
|
||||
app.use(`/icon.png`, express.static(path.join(publicAssetsDir, "icon.png"), STATIC_OPTIONS));
|
||||
|
||||
const { default: sessionParser, startSessionCleanup } = await import("./routes/session_parser.js");
|
||||
app.use(sessionParser);
|
||||
|
||||
@@ -365,7 +365,10 @@
|
||||
"last-updated": "Last updated on {{- date}}",
|
||||
"subpages": "Subpages:",
|
||||
"on-this-page": "On This Page",
|
||||
"expand": "Expand"
|
||||
"expand": "Expand",
|
||||
"toggle-navigation": "Toggle Navigation",
|
||||
"toggle-toc": "Toggle Table of Contents",
|
||||
"logo-alt": "Logo"
|
||||
},
|
||||
"hidden_subtree_templates": {
|
||||
"text-snippet": "Text Snippet",
|
||||
|
||||
@@ -9,6 +9,9 @@ import auth from "../services/auth.js";
|
||||
import { getResourceDir, isDev } from "../services/utils.js";
|
||||
import { doubleCsrfProtection as csrfMiddleware } from "./csrf_protection.js";
|
||||
|
||||
// Allow serving assets even if the installation path contains a hidden (dot-prefixed) directory.
|
||||
const STATIC_OPTIONS: serveStatic.ServeStaticOptions = { dotfiles: "allow" };
|
||||
|
||||
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
|
||||
if (!isDev) {
|
||||
options = {
|
||||
@@ -16,7 +19,7 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
|
||||
...options
|
||||
};
|
||||
}
|
||||
return express.static(root, options);
|
||||
return express.static(root, { ...STATIC_OPTIONS, ...options });
|
||||
};
|
||||
|
||||
async function register(app: express.Application) {
|
||||
@@ -66,7 +69,7 @@ async function register(app: express.Application) {
|
||||
// broken when closing the browser and coming back in to the page.
|
||||
// The page is restored from cache, but the API call fail.
|
||||
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
res.sendFile(path.join(publicDir, "index.html"));
|
||||
res.sendFile(path.join(publicDir, "index.html"), STATIC_OPTIONS);
|
||||
});
|
||||
app.use("/assets", persistentCacheStatic(path.join(publicDir, "assets")));
|
||||
app.use(`/src`, persistentCacheStatic(path.join(publicDir, "src")));
|
||||
@@ -76,14 +79,14 @@ async function register(app: express.Application) {
|
||||
app.use(`/${assetUrlFragment}/translations/`, persistentCacheStatic(path.join(publicDir, "translations")));
|
||||
app.use(`/node_modules/`, persistentCacheStatic(path.join(publicDir, "node_modules")));
|
||||
}
|
||||
app.use(`/share/assets/fonts/`, express.static(path.join(getClientDir(), "fonts")));
|
||||
app.use(`/share/assets/`, express.static(getShareThemeAssetDir()));
|
||||
app.use(`/share/assets/fonts/`, express.static(path.join(getClientDir(), "fonts"), STATIC_OPTIONS));
|
||||
app.use(`/share/assets/`, express.static(getShareThemeAssetDir(), STATIC_OPTIONS));
|
||||
app.use(`/pdfjs/`, persistentCacheStatic(getPdfjsAssetDir()));
|
||||
app.use(`/${assetUrlFragment}/images`, persistentCacheStatic(path.join(resourceDir, "assets", "images")));
|
||||
app.use(`/${assetUrlFragment}/doc_notes`, persistentCacheStatic(path.join(resourceDir, "assets", "doc_notes")));
|
||||
app.use(`/assets/vX/fonts`, express.static(path.join(srcRoot, "public/fonts")));
|
||||
app.use(`/assets/vX/images`, express.static(path.join(srcRoot, "..", "images")));
|
||||
app.use(`/assets/vX/stylesheets`, express.static(path.join(srcRoot, "public/stylesheets")));
|
||||
app.use(`/assets/vX/fonts`, express.static(path.join(srcRoot, "public/fonts"), STATIC_OPTIONS));
|
||||
app.use(`/assets/vX/images`, express.static(path.join(srcRoot, "..", "images"), STATIC_OPTIONS));
|
||||
app.use(`/assets/vX/stylesheets`, express.static(path.join(srcRoot, "public/stylesheets"), STATIC_OPTIONS));
|
||||
}
|
||||
|
||||
export function getShareThemeAssetDir() {
|
||||
|
||||
@@ -148,8 +148,8 @@ export function renderNoteContent(note: SNote) {
|
||||
isStatic: false,
|
||||
faviconUrl: note.hasRelation("shareFavicon") ? `api/notes/${note.getRelationValue("shareFavicon")}/download` : `../favicon.ico`,
|
||||
iconPackCss: iconPacks.map(p => iconPackService.generateCss(p, p.builtin
|
||||
? `/share/assets/fonts/${p.fontAttachmentId}.${iconPackService.MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}`
|
||||
: `/share/api/attachments/${p.fontAttachmentId}/download`
|
||||
? `assets/fonts/${p.fontAttachmentId}.${iconPackService.MIME_TO_EXTENSION_MAPPINGS[p.fontMime]}`
|
||||
: `api/attachments/${p.fontAttachmentId}/download`
|
||||
))
|
||||
.filter(Boolean)
|
||||
.join("\n\n"),
|
||||
|
||||
@@ -56,13 +56,20 @@ export default class NodejsZipProvider implements ZipProvider {
|
||||
processEntry: (entry: ZipEntry, readContent: () => Promise<Uint8Array>) => Promise<void>
|
||||
): Promise<void> {
|
||||
return new Promise<void>((res, rej) => {
|
||||
yauzl.fromBuffer(Buffer.from(buffer), { lazyEntries: true, validateEntrySizes: false }, (err, zipfile) => {
|
||||
yauzl.fromBuffer(Buffer.from(buffer), { lazyEntries: true, validateEntrySizes: false, decodeStrings: false }, (err, zipfile) => {
|
||||
if (err) { rej(err); return; }
|
||||
if (!zipfile) { rej(new Error("Unable to read zip file.")); return; }
|
||||
|
||||
zipfile.readEntry();
|
||||
zipfile.on("entry", async (entry: yauzl.Entry) => {
|
||||
try {
|
||||
// yauzl with decodeStrings: false returns fileName as a Buffer.
|
||||
// We decode as UTF-8 to handle ZIP files that use UTF-8 filenames
|
||||
// without setting the general purpose bit flag 11 (language encoding flag).
|
||||
const fileName = Buffer.isBuffer(entry.fileName)
|
||||
? (entry.fileName as Buffer).toString("utf-8")
|
||||
: entry.fileName;
|
||||
|
||||
const readContent = () => new Promise<Uint8Array>((res, rej) => {
|
||||
zipfile.openReadStream(entry, (err, readStream) => {
|
||||
if (err) { rej(err); return; }
|
||||
@@ -71,7 +78,7 @@ export default class NodejsZipProvider implements ZipProvider {
|
||||
});
|
||||
});
|
||||
|
||||
await processEntry({ fileName: entry.fileName }, readContent);
|
||||
await processEntry({ fileName }, readContent);
|
||||
} catch (e) {
|
||||
rej(e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user