termdock 1.4.59 → 1.4.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{ModelPreview-DH-7pHJF.js → ModelPreview-B1OvdY6Y.js} +1 -1
- package/dist/client/assets/{abnfDiagram-VRR7QNED-Ct00-XnB.js → abnfDiagram-VRR7QNED-D2uLqeI6.js} +1 -1
- package/dist/client/assets/{arc-BbTXkvLg.js → arc-DaliyFqT.js} +1 -1
- package/dist/client/assets/{architectureDiagram-ZJ3FMSHR-CmuzCqen.js → architectureDiagram-ZJ3FMSHR-Ci9AYtfI.js} +1 -1
- package/dist/client/assets/{blockDiagram-677ZJIJ3-CCluwOk7.js → blockDiagram-677ZJIJ3-tpKuazu8.js} +1 -1
- package/dist/client/assets/{c4Diagram-LMCZKHZV-BIKbP4LS.js → c4Diagram-LMCZKHZV-DBZ0GqHZ.js} +1 -1
- package/dist/client/assets/channel-DDepQdrD.js +1 -0
- package/dist/client/assets/{chunk-2Q5K7J3B-BDwk6RC_.js → chunk-2Q5K7J3B-cH16Qvz-.js} +1 -1
- package/dist/client/assets/{chunk-32BRIVSS-DnwdpIMs.js → chunk-32BRIVSS-BuknZPoV.js} +1 -1
- package/dist/client/assets/{chunk-5VM5RSS4-CwCLJYkK.js → chunk-5VM5RSS4-CakI4HDi.js} +1 -1
- package/dist/client/assets/{chunk-EX3LRPZG-BOZ7Q5SG.js → chunk-EX3LRPZG-BMRvbF-Z.js} +1 -1
- package/dist/client/assets/{chunk-JWPE2WC7-BRP7egWP.js → chunk-JWPE2WC7-DxwG2oXx.js} +1 -1
- package/dist/client/assets/{chunk-MOJQB5TN-DjR8pTwa.js → chunk-MOJQB5TN-DsrI6VNx.js} +1 -1
- package/dist/client/assets/{chunk-RYQCIY6F-Cd7R_v4u.js → chunk-RYQCIY6F-DMZtuC2G.js} +1 -1
- package/dist/client/assets/{chunk-V7JOEXUC-B5mnq3DX.js → chunk-V7JOEXUC-C0MJdNRw.js} +1 -1
- package/dist/client/assets/{chunk-VR4S4FIN-Dc58ALhF.js → chunk-VR4S4FIN-CqXqVOfm.js} +1 -1
- package/dist/client/assets/{chunk-XXDRQBXY-BlHAakeI.js → chunk-XXDRQBXY-B3Vukuxf.js} +1 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-D8FEkYqo.js +1 -0
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-D8FEkYqo.js +1 -0
- package/dist/client/assets/{cose-bilkent-JH36ORCC-CVfKk5v7.js → cose-bilkent-JH36ORCC-B-VQvkDs.js} +1 -1
- package/dist/client/assets/{cynefin-VYW2F7L2-DFwNttbS.js → cynefin-VYW2F7L2-BrAMXJjC.js} +1 -1
- package/dist/client/assets/{cynefinDiagram-TSTJHNR4-Bh7AF6Wm.js → cynefinDiagram-TSTJHNR4-Cq9Ux3Fy.js} +1 -1
- package/dist/client/assets/{dagre-VKFMJZFB-DuSTc5Sy.js → dagre-VKFMJZFB-o8vr8ayM.js} +1 -1
- package/dist/client/assets/{diagram-FQU43EPY-C7XMbUXe.js → diagram-FQU43EPY-vbifK9a8.js} +1 -1
- package/dist/client/assets/{diagram-G47NLZAW-DZa2dWvr.js → diagram-G47NLZAW-C8-5CIhe.js} +1 -1
- package/dist/client/assets/{diagram-NH7WQ7WH-B6_wGIDm.js → diagram-NH7WQ7WH-kCznb4CY.js} +1 -1
- package/dist/client/assets/{diagram-OA4YK3LP-CHOs8m-t.js → diagram-OA4YK3LP-D_smaDEi.js} +1 -1
- package/dist/client/assets/{diagram-WEI45ONY-BDjbzb1X.js → diagram-WEI45ONY-Dhc2Lzo1.js} +1 -1
- package/dist/client/assets/{ebnfDiagram-CCIWWBDH-DARvicrf.js → ebnfDiagram-CCIWWBDH-y4ira4kc.js} +1 -1
- package/dist/client/assets/{erDiagram-Q63AITRT-AaNcwwTP.js → erDiagram-Q63AITRT-B-nhuVMi.js} +1 -1
- package/dist/client/assets/{flowDiagram-23GEKE2U-B3xYW3Ac.js → flowDiagram-23GEKE2U-Dlnwg19s.js} +1 -1
- package/dist/client/assets/{ganttDiagram-NO4QXBWP-CqG72bE2.js → ganttDiagram-NO4QXBWP-D3QwFnc7.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-IHSO6WYX-mKeuquZY.js → gitGraphDiagram-IHSO6WYX-CXrAhE6m.js} +1 -1
- package/dist/client/assets/{index-wM1B1hbM.js → index-odBJmu0C.js} +4 -4
- package/dist/client/assets/{infoDiagram-FWYZ7A6U-DPAUPRi0.js → infoDiagram-FWYZ7A6U-DFgLQ4y2.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-FXEZZL3T-D-6UZHyN.js → ishikawaDiagram-FXEZZL3T-BCYpHWRD.js} +1 -1
- package/dist/client/assets/{journeyDiagram-5HDEW3XC-DOZJ9ip9.js → journeyDiagram-5HDEW3XC-CrZXynFO.js} +1 -1
- package/dist/client/assets/{kanban-definition-HUTT4EX6-DB3ae5AM.js → kanban-definition-HUTT4EX6-BXJ_dJl2.js} +1 -1
- package/dist/client/assets/{linear-Bha1cE7s.js → linear-DtRhyTE2.js} +1 -1
- package/dist/client/assets/{mermaid.core-DSPzdUTe.js → mermaid.core-CCIaRGmw.js} +4 -4
- package/dist/client/assets/{mindmap-definition-LN4V7U3C-DKKUZo_x.js → mindmap-definition-LN4V7U3C-BG7KaQs9.js} +1 -1
- package/dist/client/assets/{pegDiagram-2B236MQR-DaV3xDvd.js → pegDiagram-2B236MQR-Ca8VQuCx.js} +1 -1
- package/dist/client/assets/{pieDiagram-ENE6RG2P-DVkjTBsT.js → pieDiagram-ENE6RG2P-peMbHrUv.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-ABIIQ3AL-C-bZjtId.js → quadrantDiagram-ABIIQ3AL-C8Hslb7e.js} +1 -1
- package/dist/client/assets/{railroadDiagram-RFXS5EU6-Cf0UEv0O.js → railroadDiagram-RFXS5EU6-s9X0vHjC.js} +1 -1
- package/dist/client/assets/{requirementDiagram-TGXJPOKE-VIxA-DHJ.js → requirementDiagram-TGXJPOKE-DGFtY61L.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-HTMAVEWB-B7cqKt39.js → sankeyDiagram-HTMAVEWB-FjpXm1PE.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-DBY2YBRQ-DB52or-d.js → sequenceDiagram-DBY2YBRQ-el30tdD1.js} +1 -1
- package/dist/client/assets/{sizeCapture-X5ZJPWSS-C-Hy7dNK.js → sizeCapture-X5ZJPWSS-s0vjhQbx.js} +1 -1
- package/dist/client/assets/{stateDiagram-2N3HPSRC-CrjCbVZF.js → stateDiagram-2N3HPSRC-INN3jV4e.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-Cv_lT9Rz.js +1 -0
- package/dist/client/assets/{swimlanes-5IMT3BWC-C2UEDf_r.js → swimlanes-5IMT3BWC-BqRo4MVX.js} +2 -2
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-BGyXfDpF.js +8 -0
- package/dist/client/assets/{timeline-definition-FHXFAJF6-Cz7nYQhl.js → timeline-definition-FHXFAJF6-BKfa2cCe.js} +1 -1
- package/dist/client/assets/{vennDiagram-L72KCM5P-DPs4clHV.js → vennDiagram-L72KCM5P-jNwIHGea.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-EHGQE667-Bd39mz6c.js → wardleyDiagram-EHGQE667-BQBZ6FiY.js} +1 -1
- package/dist/client/assets/{xychartDiagram-FW5EYKEG-B8RKfuGf.js → xychartDiagram-FW5EYKEG-fmWk1_uE.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/client/sw.js +1 -1
- package/dist/server/entry.js +5 -1
- package/dist/server/routes/filesystem.js +140 -25
- package/dist/server/utils/authProtection.js +3 -1
- package/package.json +1 -1
- package/runtime-manifest.json +2 -2
- package/dist/client/assets/channel-LdBDFRps.js +0 -1
- package/dist/client/assets/classDiagram-OUVF2IWQ-B836Ofsf.js +0 -1
- package/dist/client/assets/classDiagram-v2-EOCWNBFH-B836Ofsf.js +0 -1
- package/dist/client/assets/stateDiagram-v2-6OUMAXLB-DXnU7NjN.js +0 -1
- package/dist/client/assets/swimlanesDiagram-G3AALYLV-DTDpRtmY.js +0 -8
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
+
import crypto from 'crypto';
|
|
2
3
|
import fs from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import { execFile, spawn } from 'child_process';
|
|
5
6
|
import watcher from '@parcel/watcher';
|
|
6
7
|
import busboy from 'busboy';
|
|
7
8
|
import { pathValidator } from '../utils/pathValidator.js';
|
|
9
|
+
import { isAuthEnabled, isRequestAuthenticated } from '../utils/authProtection.js';
|
|
8
10
|
import { getImageDimensions } from '../utils/imageDimensions.js';
|
|
9
11
|
import { writeDiffTraceLog, writeErrorLog, writeJsonLog } from '../utils/serverLogger.js';
|
|
10
12
|
import { clearBranchAuditRecords, clearChangeAuditRecords, listBranchAuditRecords, listChangeAuditRecords, buildChangeAuditFingerprint } from '../utils/changeAuditStore.js';
|
|
@@ -2956,21 +2958,59 @@ router.get('/video', async (req, res) => {
|
|
|
2956
2958
|
// index.html), so relative css/js/image references inside a document resolve
|
|
2957
2959
|
// to the file's own directory. To make that resolution explicit and engine-
|
|
2958
2960
|
// independent (some engines don't reliably resolve subresources against a
|
|
2959
|
-
// sandboxed iframe's document URL), HTML documents get an injected
|
|
2960
|
-
//
|
|
2961
|
-
//
|
|
2962
|
-
//
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2961
|
+
// sandboxed iframe's document URL), HTML documents get an injected <base href>
|
|
2962
|
+
// equal to the document's own request URL — that keeps relative references
|
|
2963
|
+
// working while also making in-page anchor links (#section) stay same-document
|
|
2964
|
+
// instead of forcing a full reload. Other asset types keep streaming as-is.
|
|
2965
|
+
//
|
|
2966
|
+
// Authentication: browsers refuse to send cookies for subresource requests
|
|
2967
|
+
// from a sandboxed iframe without allow-same-origin (Chrome blocks the 401
|
|
2968
|
+
// responses as ORB), so with a password set the document loads but images
|
|
2969
|
+
// don't. The preview route therefore authenticates document requests with the
|
|
2970
|
+
// session cookie, then redirects them to a URL carrying a short-lived token
|
|
2971
|
+
// bound to the previewed file's directory. Every relative subresource URL
|
|
2972
|
+
// inherits that token from the document URL, so css/js/images load without
|
|
2973
|
+
// cookies while the sandbox keeps previewed scripts on a separate origin.
|
|
2974
|
+
// The frontend renders this in a sandboxed iframe (no allow-same-origin), so
|
|
2975
|
+
// previewed scripts never gain the termdock origin.
|
|
2976
|
+
const PREVIEW_TOKEN_TTL_MS = 30 * 60 * 1000;
|
|
2977
|
+
const previewTokens = new Map();
|
|
2978
|
+
export function isPreviewToken(value) {
|
|
2979
|
+
return /^[0-9a-f]{32}$/.test(value);
|
|
2980
|
+
}
|
|
2981
|
+
export function isPathWithinPreviewRoot(root, targetPath) {
|
|
2982
|
+
const resolvedRoot = path.resolve(root);
|
|
2983
|
+
const resolvedTarget = path.resolve(targetPath);
|
|
2984
|
+
const prefix = resolvedRoot.endsWith(path.sep) ? resolvedRoot : `${resolvedRoot}${path.sep}`;
|
|
2985
|
+
return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(prefix);
|
|
2986
|
+
}
|
|
2987
|
+
// Sliding-expiry validation: a valid token refreshes its lifetime so a page
|
|
2988
|
+
// that keeps loading subresources stays usable without re-authenticating.
|
|
2989
|
+
export function validatePreviewToken(token, targetPath) {
|
|
2990
|
+
const entry = previewTokens.get(token);
|
|
2991
|
+
if (!entry)
|
|
2992
|
+
return false;
|
|
2993
|
+
if (entry.expiresAt < Date.now()) {
|
|
2994
|
+
previewTokens.delete(token);
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
if (!isPathWithinPreviewRoot(entry.root, targetPath))
|
|
2998
|
+
return false;
|
|
2999
|
+
entry.expiresAt = Date.now() + PREVIEW_TOKEN_TTL_MS;
|
|
3000
|
+
return true;
|
|
3001
|
+
}
|
|
3002
|
+
export function mintPreviewToken(root) {
|
|
3003
|
+
const now = Date.now();
|
|
3004
|
+
for (const [token, entry] of previewTokens) {
|
|
3005
|
+
if (entry.expiresAt < now)
|
|
3006
|
+
previewTokens.delete(token);
|
|
3007
|
+
}
|
|
3008
|
+
const token = crypto.randomBytes(16).toString('hex');
|
|
3009
|
+
previewTokens.set(token, { root: path.resolve(root), expiresAt: now + PREVIEW_TOKEN_TTL_MS });
|
|
3010
|
+
return token;
|
|
3011
|
+
}
|
|
3012
|
+
function tokenizePreviewUrl(previewBaseUrl, token) {
|
|
3013
|
+
return previewBaseUrl.replace(/^(\/api\/terminal\/fs\/preview\/)/, `$1${token}/`);
|
|
2974
3014
|
}
|
|
2975
3015
|
// Insert <base href> right after <head> (or after the doctype / at the very
|
|
2976
3016
|
// start when the document has no head). Documents that already declare their
|
|
@@ -2990,22 +3030,92 @@ export function injectHtmlPreviewBase(html, baseUrl) {
|
|
|
2990
3030
|
}
|
|
2991
3031
|
return baseTag + html;
|
|
2992
3032
|
}
|
|
3033
|
+
const HTML_PREVIEW_INDEX_FILES = ['index.html', 'index.htm'];
|
|
3034
|
+
// Directory navigation in a previewed document (e.g. <a href="docs/">) should
|
|
3035
|
+
// behave like a normal web server: serve the directory's index document when
|
|
3036
|
+
// one exists. Returns the validated index file path, or null when the
|
|
3037
|
+
// directory has no index to preview.
|
|
3038
|
+
export async function findDirectoryIndexFile(dirPath) {
|
|
3039
|
+
for (const name of HTML_PREVIEW_INDEX_FILES) {
|
|
3040
|
+
const candidate = path.join(dirPath, name);
|
|
3041
|
+
try {
|
|
3042
|
+
const candidatePath = await pathValidator.validatePathAsync(candidate);
|
|
3043
|
+
const candidateStat = await fs.promises.stat(candidatePath);
|
|
3044
|
+
if (candidateStat.isFile())
|
|
3045
|
+
return candidatePath;
|
|
3046
|
+
}
|
|
3047
|
+
catch {
|
|
3048
|
+
// Missing or not allowed — try the next index name.
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
3051
|
+
return null;
|
|
3052
|
+
}
|
|
2993
3053
|
router.get('/preview/*path', async (req, res) => {
|
|
2994
3054
|
try {
|
|
2995
3055
|
const rawSegments = req.params.path;
|
|
2996
3056
|
const segments = Array.isArray(rawSegments) ? rawSegments : rawSegments ? [rawSegments] : [];
|
|
2997
|
-
const
|
|
3057
|
+
const firstSegment = segments[0];
|
|
3058
|
+
const maybeToken = firstSegment && isPreviewToken(firstSegment) ? firstSegment : null;
|
|
3059
|
+
const pathSegments = maybeToken ? segments.slice(1) : segments;
|
|
3060
|
+
const requestedPath = `/${pathSegments.join('/')}`;
|
|
2998
3061
|
if (!requestedPath || requestedPath === '/') {
|
|
2999
3062
|
res.status(400).json({ error: 'Missing path parameter' });
|
|
3000
3063
|
return;
|
|
3001
3064
|
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3065
|
+
// Raw (percent-encoded) full pathname as the browser sees it (baseUrl +
|
|
3066
|
+
// path, since this router is mounted under /api/terminal/fs); used as the
|
|
3067
|
+
// injected <base> so it always equals the document URL.
|
|
3068
|
+
const previewBaseUrl = req.originalUrl.split('?', 1)[0];
|
|
3069
|
+
const authEnabled = isAuthEnabled();
|
|
3070
|
+
// Token requests carry their own credential in the URL. Document requests
|
|
3071
|
+
// must present the session cookie before we mint a token for them.
|
|
3072
|
+
if (!maybeToken && authEnabled && !isRequestAuthenticated(req)) {
|
|
3073
|
+
res.status(401).json({ error: 'Authentication required', code: 'AUTH_REQUIRED' });
|
|
3074
|
+
return;
|
|
3075
|
+
}
|
|
3076
|
+
const validatedPath = await pathValidator.validatePathAsync(requestedPath);
|
|
3077
|
+
let stat = await fs.promises.stat(validatedPath);
|
|
3078
|
+
let targetPath = validatedPath;
|
|
3079
|
+
let redirectUrl = null;
|
|
3080
|
+
if (stat.isDirectory()) {
|
|
3081
|
+
// Directory links must carry a trailing slash so relative references
|
|
3082
|
+
// inside the served index resolve within the directory, matching how a
|
|
3083
|
+
// normal web server behaves.
|
|
3084
|
+
if (!previewBaseUrl.endsWith('/')) {
|
|
3085
|
+
redirectUrl = `${previewBaseUrl}/`;
|
|
3086
|
+
}
|
|
3087
|
+
else {
|
|
3088
|
+
const indexPath = await findDirectoryIndexFile(validatedPath);
|
|
3089
|
+
if (!indexPath) {
|
|
3090
|
+
res.status(404).json({ error: 'Directory has no index file to preview', code: 'NO_INDEX' });
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
targetPath = indexPath;
|
|
3094
|
+
stat = await fs.promises.stat(targetPath);
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
// Authenticated document requests get a short-lived token bound to the
|
|
3098
|
+
// previewed file's directory, so the sandboxed iframe's subresources can
|
|
3099
|
+
// load without cookies. The token segment in the URL is inherited by every
|
|
3100
|
+
// relative reference the document makes.
|
|
3101
|
+
if (authEnabled && !maybeToken) {
|
|
3102
|
+
const root = stat.isDirectory() ? validatedPath : path.dirname(validatedPath);
|
|
3103
|
+
const tokenized = tokenizePreviewUrl(previewBaseUrl, mintPreviewToken(root));
|
|
3104
|
+
redirectUrl = stat.isDirectory() && !previewBaseUrl.endsWith('/') ? `${tokenized}/` : tokenized;
|
|
3105
|
+
}
|
|
3106
|
+
if (redirectUrl) {
|
|
3107
|
+
res.redirect(302, redirectUrl);
|
|
3108
|
+
return;
|
|
3109
|
+
}
|
|
3004
3110
|
if (!stat.isFile()) {
|
|
3005
3111
|
res.status(400).json({ error: 'Path is not a file' });
|
|
3006
3112
|
return;
|
|
3007
3113
|
}
|
|
3008
|
-
|
|
3114
|
+
if (maybeToken && !validatePreviewToken(maybeToken, targetPath)) {
|
|
3115
|
+
res.status(403).json({ error: 'Preview token invalid or expired', code: 'PREVIEW_TOKEN_INVALID' });
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
const mimeType = getHtmlPreviewMimeType(targetPath);
|
|
3009
3119
|
if (!mimeType) {
|
|
3010
3120
|
res.status(415).json({ error: 'Unsupported file type for preview' });
|
|
3011
3121
|
return;
|
|
@@ -3019,19 +3129,23 @@ router.get('/preview/*path', async (req, res) => {
|
|
|
3019
3129
|
});
|
|
3020
3130
|
return;
|
|
3021
3131
|
}
|
|
3022
|
-
const isHtml = path.extname(
|
|
3132
|
+
const isHtml = path.extname(targetPath).toLowerCase() === '.html' || path.extname(targetPath).toLowerCase() === '.htm';
|
|
3023
3133
|
if (isHtml) {
|
|
3024
3134
|
// HTML is size-capped above; buffer it so we can inject <base> and send
|
|
3025
3135
|
// an accurate Content-Length for the modified payload.
|
|
3026
|
-
const html = await fs.promises.readFile(
|
|
3027
|
-
const served = injectHtmlPreviewBase(html,
|
|
3136
|
+
const html = await fs.promises.readFile(targetPath, 'utf8');
|
|
3137
|
+
const served = injectHtmlPreviewBase(html, previewBaseUrl);
|
|
3028
3138
|
const payload = Buffer.from(served, 'utf8');
|
|
3029
3139
|
res.setHeader('Content-Type', mimeType);
|
|
3030
3140
|
res.setHeader('Content-Length', payload.length.toString());
|
|
3031
3141
|
res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
|
3032
3142
|
res.setHeader('Cache-Control', 'no-store');
|
|
3033
3143
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
3034
|
-
|
|
3144
|
+
// Preview URLs carry a short-lived token; never leak it to third-party
|
|
3145
|
+
// resources the previewed document loads (fonts, analytics, hotlinked
|
|
3146
|
+
// images) via the Referer header.
|
|
3147
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
3148
|
+
res.setHeader('Content-Disposition', buildContentDisposition('inline', path.basename(targetPath)));
|
|
3035
3149
|
res.end(payload);
|
|
3036
3150
|
return;
|
|
3037
3151
|
}
|
|
@@ -3040,8 +3154,9 @@ router.get('/preview/*path', async (req, res) => {
|
|
|
3040
3154
|
res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
|
3041
3155
|
res.setHeader('Cache-Control', 'no-store');
|
|
3042
3156
|
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
3043
|
-
res.setHeader('
|
|
3044
|
-
|
|
3157
|
+
res.setHeader('Referrer-Policy', 'no-referrer');
|
|
3158
|
+
res.setHeader('Content-Disposition', buildContentDisposition('inline', path.basename(targetPath)));
|
|
3159
|
+
const stream = fs.createReadStream(targetPath);
|
|
3045
3160
|
stream.on('error', (error) => {
|
|
3046
3161
|
if (!res.headersSent) {
|
|
3047
3162
|
const message = error instanceof Error ? error.message : 'Failed to serve file';
|
|
@@ -277,10 +277,12 @@ export function isRequestAuthenticated(req) {
|
|
|
277
277
|
// Middleware factory: blocks the request with 401 unless either auth is
|
|
278
278
|
// disabled (no auth.json) or the request carries a valid session cookie.
|
|
279
279
|
// Bypass paths are public (login/status/health/static).
|
|
280
|
-
export function requireAuth() {
|
|
280
|
+
export function requireAuth(options) {
|
|
281
281
|
return (req, res, next) => {
|
|
282
282
|
if (!isAuthEnabled())
|
|
283
283
|
return next();
|
|
284
|
+
if (options?.bypass?.(req))
|
|
285
|
+
return next();
|
|
284
286
|
if (isRequestAuthenticated(req))
|
|
285
287
|
return next();
|
|
286
288
|
res.status(401).json({ error: 'Authentication required', code: 'AUTH_REQUIRED' });
|
package/package.json
CHANGED
package/runtime-manifest.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "termdock",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.61",
|
|
5
5
|
"runtimeProtocolVersion": 1,
|
|
6
6
|
"minimumDesktopVersion": "1.4.46",
|
|
7
7
|
"nodeMajor": 22,
|
|
8
8
|
"dependencyHash": "sha256-HxC6p3b4kFesefw+vmNYJtPtdIKJaZR1jFNb7DRJqjU=",
|
|
9
|
-
"serverBundleHash": "sha256-
|
|
9
|
+
"serverBundleHash": "sha256-LCn7H9Y5FsrDIW4fPGpMsIQKA6h6pY/QNFtpIb/cARM=",
|
|
10
10
|
"entrypoint": "dist/server/cli.js",
|
|
11
11
|
"clientEntrypoint": "dist/client/index.html"
|
|
12
12
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{U as a,C as n}from"./mermaid.core-DSPzdUTe.js";const t=(r,o)=>a.lang.round(n.parse(r)[o]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-B5mnq3DX.js";import{b as i}from"./mermaid.core-DSPzdUTe.js";import"./chunk-5VM5RSS4-CwCLJYkK.js";import"./chunk-XXDRQBXY-BlHAakeI.js";import"./chunk-VR4S4FIN-Dc58ALhF.js";import"./chunk-32BRIVSS-DnwdpIMs.js";import"./purify.es-CC4Brkr_.js";import"./index-wM1B1hbM.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,a as s,c as t,C as e}from"./chunk-V7JOEXUC-B5mnq3DX.js";import{b as i}from"./mermaid.core-DSPzdUTe.js";import"./chunk-5VM5RSS4-CwCLJYkK.js";import"./chunk-XXDRQBXY-BlHAakeI.js";import"./chunk-VR4S4FIN-Dc58ALhF.js";import"./chunk-32BRIVSS-DnwdpIMs.js";import"./purify.es-CC4Brkr_.js";import"./index-wM1B1hbM.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:t,get db(){return new e},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r,a as e,s as a,S as i}from"./chunk-EX3LRPZG-BOZ7Q5SG.js";import{b as s}from"./mermaid.core-DSPzdUTe.js";import"./chunk-XXDRQBXY-BlHAakeI.js";import"./chunk-VR4S4FIN-Dc58ALhF.js";import"./chunk-32BRIVSS-DnwdpIMs.js";import"./purify.es-CC4Brkr_.js";import"./index-wM1B1hbM.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var g={parser:a,get db(){return new i(2)},renderer:e,styles:r,init:s(t=>{t.state||(t.state={}),t.state.arrowMarkerAbsolute=t.arrowMarkerAbsolute},"init")};export{g as diagram};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{c as r,s as e}from"./flowDiagram-23GEKE2U-B3xYW3Ac.js";import{b as o}from"./mermaid.core-DSPzdUTe.js";import"./chunk-5VM5RSS4-CwCLJYkK.js";import"./chunk-XXDRQBXY-BlHAakeI.js";import"./chunk-VR4S4FIN-Dc58ALhF.js";import"./chunk-32BRIVSS-DnwdpIMs.js";import"./purify.es-CC4Brkr_.js";import"./channel-LdBDFRps.js";import"./index-wM1B1hbM.js";import"./react-XDCjal2T.js";import"./dnd-BCFAPC0L.js";import"./terminal-C7X98Amf.js";var a=o(t=>`${e(t)}
|
|
2
|
-
.swimlane.cluster rect {
|
|
3
|
-
stroke: ${t.clusterBorder} !important;
|
|
4
|
-
}
|
|
5
|
-
[data-look="neo"].cluster rect {
|
|
6
|
-
filter: none;
|
|
7
|
-
}
|
|
8
|
-
`,"getStyles"),m=a,v=r({defaultLayout:"swimlane",styles:m});export{v as diagram};
|