@yadsh/dsh-qa-surface 0.6.1 → 0.7.1
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/README.md +163 -7
- package/capability-policy.json +1 -1
- package/lib/access/capability-catalog.js +144 -0
- package/lib/access/capability-catalog.js.map +1 -0
- package/lib/access/model.js +379 -0
- package/lib/access/model.js.map +1 -0
- package/lib/access/role-repository.js +195 -0
- package/lib/access/role-repository.js.map +1 -0
- package/lib/access/service.js +380 -0
- package/lib/access/service.js.map +1 -0
- package/lib/access/skill-metadata.js +234 -0
- package/lib/access/skill-metadata.js.map +1 -0
- package/lib/account-remotes.js +20 -10
- package/lib/account-remotes.js.map +1 -1
- package/lib/accounts/errors.js.map +1 -1
- package/lib/accounts/file.js.map +1 -1
- package/lib/accounts/store.js +202 -3
- package/lib/accounts/store.js.map +1 -1
- package/lib/admin/conversation-log.js +256 -0
- package/lib/admin/conversation-log.js.map +1 -0
- package/lib/admin/index.js +17 -0
- package/lib/admin/index.js.map +1 -0
- package/lib/admin/metrics.js +103 -0
- package/lib/admin/metrics.js.map +1 -0
- package/lib/admin/paging.js +23 -0
- package/lib/admin/paging.js.map +1 -0
- package/lib/admin/permissions.js +50 -0
- package/lib/admin/permissions.js.map +1 -0
- package/lib/admin/quality-store.js +485 -0
- package/lib/admin/quality-store.js.map +1 -0
- package/lib/admin/queue.js +107 -0
- package/lib/admin/queue.js.map +1 -0
- package/lib/admin/redaction.js +45 -0
- package/lib/admin/redaction.js.map +1 -0
- package/lib/admin/service.js +897 -0
- package/lib/admin/service.js.map +1 -0
- package/lib/admin/session-log.js +142 -0
- package/lib/admin/session-log.js.map +1 -0
- package/lib/cli.js +9 -6
- package/lib/cli.js.map +1 -1
- package/lib/client/QaSessionController.js +28 -2
- package/lib/client/QaSessionController.js.map +1 -1
- package/lib/client/QaSurface.js +143 -5
- package/lib/client/QaSurface.js.map +1 -1
- package/lib/client/QaTranscriptAdapter.js +1 -0
- package/lib/client/QaTranscriptAdapter.js.map +1 -1
- package/lib/client/admin/QaAdmin.js +458 -0
- package/lib/client/admin/QaAdmin.js.map +1 -0
- package/lib/client/admin/format.js +177 -0
- package/lib/client/admin/format.js.map +1 -0
- package/lib/client/admin/pages/Conversations.js +114 -0
- package/lib/client/admin/pages/Conversations.js.map +1 -0
- package/lib/client/admin/pages/Overview.js +24 -0
- package/lib/client/admin/pages/Overview.js.map +1 -0
- package/lib/client/admin/pages/Quality.js +71 -0
- package/lib/client/admin/pages/Quality.js.map +1 -0
- package/lib/client/admin/pages/Review.js +93 -0
- package/lib/client/admin/pages/Review.js.map +1 -0
- package/lib/client/admin/pages/Users.js +95 -0
- package/lib/client/admin/pages/Users.js.map +1 -0
- package/lib/client/admin/routes.js +143 -0
- package/lib/client/admin/routes.js.map +1 -0
- package/lib/client/admin/shared.js +91 -0
- package/lib/client/admin/shared.js.map +1 -0
- package/lib/client/admin/styles.js +111 -0
- package/lib/client/admin/styles.js.map +1 -0
- package/lib/client/components/QaChangelog.js +53 -0
- package/lib/client/components/QaChangelog.js.map +1 -1
- package/lib/client/components/QaHeader.js +3 -3
- package/lib/client/components/QaHeader.js.map +1 -1
- package/lib/client/components/QaMessage.js +61 -2
- package/lib/client/components/QaMessage.js.map +1 -1
- package/lib/client/create-session.js +1 -1
- package/lib/client/create-session.js.map +1 -1
- package/lib/client/index.js +48 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/role/RoleSelector.js +31 -0
- package/lib/client/role/RoleSelector.js.map +1 -0
- package/lib/client/session-sources.js +37 -1
- package/lib/client/session-sources.js.map +1 -1
- package/lib/client/settings/card.js +2 -2
- package/lib/client/settings/card.js.map +1 -1
- package/lib/client/settings/sections.js +0 -1
- package/lib/client/settings/sections.js.map +1 -1
- package/lib/client/settings-extensions/index.js +1 -0
- package/lib/client/settings-extensions/index.js.map +1 -1
- package/lib/client/settings-extensions/user-session.js +62 -0
- package/lib/client/settings-extensions/user-session.js.map +1 -0
- package/lib/client/styles.js +31 -0
- package/lib/client/styles.js.map +1 -1
- package/lib/client/types.js.map +1 -1
- package/lib/client.js +9993 -4848
- package/lib/client.js.map +1 -1
- package/lib/config-resolvers/defaults.js +0 -2
- package/lib/config-resolvers/defaults.js.map +1 -1
- package/lib/config.js +0 -249
- package/lib/config.js.map +1 -1
- package/lib/enforcement/skill-policy.js +172 -0
- package/lib/enforcement/skill-policy.js.map +1 -0
- package/lib/enforcement/tool-grants.js +151 -0
- package/lib/enforcement/tool-grants.js.map +1 -0
- package/lib/index.js +224 -42
- package/lib/index.js.map +1 -1
- package/lib/personal-skills/service.js +10 -3
- package/lib/personal-skills/service.js.map +1 -1
- package/lib/qa-tools/index.js +4 -0
- package/lib/qa-tools/index.js.map +1 -1
- package/lib/resolve-config.js +0 -2
- package/lib/resolve-config.js.map +1 -1
- package/lib/secure-session.js +71 -17
- package/lib/secure-session.js.map +1 -1
- package/lib/typert.host.js +2237 -202
- package/lib/typert.remote-client.d.ts +49 -3
- package/lib/typert.remote-client.js +1863 -183
- package/lib/types/access/capability-catalog.d.ts +37 -0
- package/lib/types/access/model.d.ts +60 -0
- package/lib/types/access/role-repository.d.ts +32 -0
- package/lib/types/access/service.d.ts +57 -0
- package/lib/types/access/skill-metadata.d.ts +53 -0
- package/lib/types/account-remotes.d.ts +6 -0
- package/lib/types/accounts/errors.d.ts +1 -1
- package/lib/types/accounts/file.d.ts +16 -5
- package/lib/types/accounts/store.d.ts +83 -3
- package/lib/types/admin/conversation-log.d.ts +39 -0
- package/lib/types/admin/index.d.ts +24 -0
- package/lib/types/admin/metrics.d.ts +29 -0
- package/lib/types/admin/paging.d.ts +33 -0
- package/lib/types/admin/permissions.d.ts +10 -0
- package/lib/types/admin/quality-store.d.ts +82 -0
- package/lib/types/admin/queue.d.ts +21 -0
- package/lib/types/admin/redaction.d.ts +29 -0
- package/lib/types/admin/service.d.ts +105 -0
- package/lib/types/admin/session-log.d.ts +53 -0
- package/lib/types/client/QaSessionController.d.ts +12 -1
- package/lib/types/client/QaSurface.d.ts +7 -1
- package/lib/types/client/admin/QaAdmin.d.ts +17 -0
- package/lib/types/client/admin/format.d.ts +43 -0
- package/lib/types/client/admin/pages/Conversations.d.ts +21 -0
- package/lib/types/client/admin/pages/Overview.d.ts +13 -0
- package/lib/types/client/admin/pages/Quality.d.ts +18 -0
- package/lib/types/client/admin/pages/Review.d.ts +15 -0
- package/lib/types/client/admin/pages/Users.d.ts +22 -0
- package/lib/types/client/admin/routes.d.ts +60 -0
- package/lib/types/client/admin/shared.d.ts +53 -0
- package/lib/types/client/admin/styles.d.ts +11 -0
- package/lib/types/client/components/QaHeader.d.ts +5 -1
- package/lib/types/client/components/QaMessage.d.ts +14 -1
- package/lib/types/client/create-session.d.ts +2 -0
- package/lib/types/client/role/RoleSelector.d.ts +14 -0
- package/lib/types/client/session-sources.d.ts +9 -0
- package/lib/types/client/settings/sections.d.ts +0 -1
- package/lib/types/client/settings-extensions/index.d.ts +2 -0
- package/lib/types/client/settings-extensions/user-session.d.ts +59 -0
- package/lib/types/client/types.d.ts +39 -2
- package/lib/types/enforcement/skill-policy.d.ts +29 -0
- package/lib/types/enforcement/tool-grants.d.ts +84 -0
- package/lib/types/index.d.ts +62 -14
- package/lib/types/qa-tools/index.d.ts +2 -0
- package/lib/types/secure-session.d.ts +10 -1
- package/lib/types/types.d.ts +568 -5
- package/package.json +2 -2
- package/lib/client/settings/sections/documents.js +0 -88
- package/lib/client/settings/sections/documents.js.map +0 -1
- package/lib/documents/artifacts/ids.js +0 -43
- package/lib/documents/artifacts/ids.js.map +0 -1
- package/lib/documents/artifacts/manifest.js +0 -66
- package/lib/documents/artifacts/manifest.js.map +0 -1
- package/lib/documents/artifacts/store.js +0 -169
- package/lib/documents/artifacts/store.js.map +0 -1
- package/lib/documents/capabilities.js +0 -93
- package/lib/documents/capabilities.js.map +0 -1
- package/lib/documents/config.js +0 -302
- package/lib/documents/config.js.map +0 -1
- package/lib/documents/defaults.js +0 -78
- package/lib/documents/defaults.js.map +0 -1
- package/lib/documents/errors.js +0 -101
- package/lib/documents/errors.js.map +0 -1
- package/lib/documents/index.js +0 -80
- package/lib/documents/index.js.map +0 -1
- package/lib/documents/inspect/facts.js +0 -161
- package/lib/documents/inspect/facts.js.map +0 -1
- package/lib/documents/inspect/zip.js +0 -108
- package/lib/documents/inspect/zip.js.map +0 -1
- package/lib/documents/markdown/directives.js +0 -135
- package/lib/documents/markdown/directives.js.map +0 -1
- package/lib/documents/markdown/frontmatter.js +0 -35
- package/lib/documents/markdown/frontmatter.js.map +0 -1
- package/lib/documents/markdown/normalize.js +0 -113
- package/lib/documents/markdown/normalize.js.map +0 -1
- package/lib/documents/orchestrator/assets.js +0 -243
- package/lib/documents/orchestrator/assets.js.map +0 -1
- package/lib/documents/orchestrator/convert-document.js +0 -186
- package/lib/documents/orchestrator/convert-document.js.map +0 -1
- package/lib/documents/orchestrator/create-document.js +0 -292
- package/lib/documents/orchestrator/create-document.js.map +0 -1
- package/lib/documents/orchestrator/extract-document.js +0 -162
- package/lib/documents/orchestrator/extract-document.js.map +0 -1
- package/lib/documents/orchestrator/inspect-document.js +0 -89
- package/lib/documents/orchestrator/inspect-document.js.map +0 -1
- package/lib/documents/orchestrator/runtime-deps.js +0 -59
- package/lib/documents/orchestrator/runtime-deps.js.map +0 -1
- package/lib/documents/orchestrator/scope.js +0 -132
- package/lib/documents/orchestrator/scope.js.map +0 -1
- package/lib/documents/providers/docling.js +0 -247
- package/lib/documents/providers/docling.js.map +0 -1
- package/lib/documents/providers/libreoffice.js +0 -130
- package/lib/documents/providers/libreoffice.js.map +0 -1
- package/lib/documents/providers/markitdown.js +0 -89
- package/lib/documents/providers/markitdown.js.map +0 -1
- package/lib/documents/providers/pandoc.js +0 -161
- package/lib/documents/providers/pandoc.js.map +0 -1
- package/lib/documents/providers/process.js +0 -164
- package/lib/documents/providers/process.js.map +0 -1
- package/lib/documents/providers/registry.js +0 -152
- package/lib/documents/providers/registry.js.map +0 -1
- package/lib/documents/providers/shared.js +0 -75
- package/lib/documents/providers/shared.js.map +0 -1
- package/lib/documents/runtime.js +0 -114
- package/lib/documents/runtime.js.map +0 -1
- package/lib/documents/security/file-types.js +0 -188
- package/lib/documents/security/file-types.js.map +0 -1
- package/lib/documents/security/limits.js +0 -78
- package/lib/documents/security/limits.js.map +0 -1
- package/lib/documents/security/mime.js +0 -43
- package/lib/documents/security/mime.js.map +0 -1
- package/lib/documents/security/paths.js +0 -133
- package/lib/documents/security/paths.js.map +0 -1
- package/lib/documents/templates/registry.js +0 -147
- package/lib/documents/templates/registry.js.map +0 -1
- package/lib/documents/templates/resolver.js +0 -59
- package/lib/documents/templates/resolver.js.map +0 -1
- package/lib/documents/tools/convert.js +0 -125
- package/lib/documents/tools/convert.js.map +0 -1
- package/lib/documents/tools/create.js +0 -187
- package/lib/documents/tools/create.js.map +0 -1
- package/lib/documents/tools/index.js +0 -41
- package/lib/documents/tools/index.js.map +0 -1
- package/lib/documents/tools/inspect.js +0 -135
- package/lib/documents/tools/inspect.js.map +0 -1
- package/lib/documents/tools/shared.js +0 -88
- package/lib/documents/tools/shared.js.map +0 -1
- package/lib/documents/tools/to-markdown.js +0 -125
- package/lib/documents/tools/to-markdown.js.map +0 -1
- package/lib/documents/types.js +0 -12
- package/lib/documents/types.js.map +0 -1
- package/lib/types/client/settings/sections/documents.d.ts +0 -13
- package/lib/types/documents/artifacts/ids.d.ts +0 -14
- package/lib/types/documents/artifacts/manifest.d.ts +0 -32
- package/lib/types/documents/artifacts/store.d.ts +0 -67
- package/lib/types/documents/capabilities.d.ts +0 -32
- package/lib/types/documents/config.d.ts +0 -27
- package/lib/types/documents/defaults.d.ts +0 -161
- package/lib/types/documents/errors.d.ts +0 -42
- package/lib/types/documents/index.d.ts +0 -63
- package/lib/types/documents/inspect/facts.d.ts +0 -43
- package/lib/types/documents/inspect/zip.d.ts +0 -28
- package/lib/types/documents/markdown/directives.d.ts +0 -39
- package/lib/types/documents/markdown/frontmatter.d.ts +0 -15
- package/lib/types/documents/markdown/normalize.d.ts +0 -30
- package/lib/types/documents/orchestrator/assets.d.ts +0 -55
- package/lib/types/documents/orchestrator/convert-document.d.ts +0 -25
- package/lib/types/documents/orchestrator/create-document.d.ts +0 -18
- package/lib/types/documents/orchestrator/extract-document.d.ts +0 -24
- package/lib/types/documents/orchestrator/inspect-document.d.ts +0 -12
- package/lib/types/documents/orchestrator/runtime-deps.d.ts +0 -43
- package/lib/types/documents/orchestrator/scope.d.ts +0 -52
- package/lib/types/documents/providers/docling.d.ts +0 -54
- package/lib/types/documents/providers/libreoffice.d.ts +0 -40
- package/lib/types/documents/providers/markitdown.d.ts +0 -28
- package/lib/types/documents/providers/pandoc.d.ts +0 -42
- package/lib/types/documents/providers/process.d.ts +0 -54
- package/lib/types/documents/providers/registry.d.ts +0 -68
- package/lib/types/documents/providers/shared.d.ts +0 -27
- package/lib/types/documents/runtime.d.ts +0 -59
- package/lib/types/documents/security/file-types.d.ts +0 -39
- package/lib/types/documents/security/limits.d.ts +0 -24
- package/lib/types/documents/security/mime.d.ts +0 -13
- package/lib/types/documents/security/paths.d.ts +0 -38
- package/lib/types/documents/templates/registry.d.ts +0 -50
- package/lib/types/documents/templates/resolver.d.ts +0 -30
- package/lib/types/documents/tools/convert.d.ts +0 -9
- package/lib/types/documents/tools/create.d.ts +0 -14
- package/lib/types/documents/tools/index.d.ts +0 -33
- package/lib/types/documents/tools/inspect.d.ts +0 -9
- package/lib/types/documents/tools/shared.d.ts +0 -77
- package/lib/types/documents/tools/to-markdown.d.ts +0 -12
- package/lib/types/documents/types.d.ts +0 -294
package/lib/documents/runtime.js
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The runtime facade the tools talk to.
|
|
3
|
-
*
|
|
4
|
-
* One instance lives in the plugin and survives across calls, so the backend
|
|
5
|
-
* registry, the concurrency semaphores and the version caches are shared
|
|
6
|
-
* instead of rebuilt per request. The four operations are the whole surface:
|
|
7
|
-
* everything else in this subsystem is an implementation detail behind them.
|
|
8
|
-
*/
|
|
9
|
-
import { ArtifactStore } from "./artifacts/store.js";
|
|
10
|
-
import { applyDocumentsEnvOverrides, resolveDocumentsConfig, } from "./config.js";
|
|
11
|
-
import { documentCapabilities, documentHealth, } from "./capabilities.js";
|
|
12
|
-
import { DocumentError } from "./errors.js";
|
|
13
|
-
import { createProviders, } from "./providers/registry.js";
|
|
14
|
-
import { convertDocument } from "./orchestrator/convert-document.js";
|
|
15
|
-
import { createDocument } from "./orchestrator/create-document.js";
|
|
16
|
-
import { inspectDocument } from "./orchestrator/inspect-document.js";
|
|
17
|
-
import { toMarkdown } from "./orchestrator/extract-document.js";
|
|
18
|
-
import { createRuntimeDeps, silentDocumentLogger, } from "./orchestrator/runtime-deps.js";
|
|
19
|
-
import { loadScopeTemplates, resolveDocumentScope, } from "./orchestrator/scope.js";
|
|
20
|
-
import { loadTemplateRegistry } from "./templates/registry.js";
|
|
21
|
-
import { CONVERSION_ROUTES } from "./orchestrator/convert-document.js";
|
|
22
|
-
export class DocumentRuntime {
|
|
23
|
-
config;
|
|
24
|
-
providers;
|
|
25
|
-
deps;
|
|
26
|
-
seams;
|
|
27
|
-
constructor(options) {
|
|
28
|
-
this.config = options.config;
|
|
29
|
-
this.seams = options.seams ?? {};
|
|
30
|
-
this.providers =
|
|
31
|
-
options.providers ?? createProviders(this.config, this.seams);
|
|
32
|
-
this.deps = createRuntimeDeps({
|
|
33
|
-
config: this.config,
|
|
34
|
-
providers: this.providers,
|
|
35
|
-
logger: options.logger ?? silentDocumentLogger,
|
|
36
|
-
...(options.now === undefined ? {} : { now: options.now }),
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
async create(input, scope) {
|
|
40
|
-
return await createDocument(this.deps, input, scope);
|
|
41
|
-
}
|
|
42
|
-
async toMarkdown(input, scope) {
|
|
43
|
-
return await toMarkdown(this.deps, input, scope);
|
|
44
|
-
}
|
|
45
|
-
async convert(input, scope) {
|
|
46
|
-
return await convertDocument(this.deps, input, scope);
|
|
47
|
-
}
|
|
48
|
-
async inspect(input, scope) {
|
|
49
|
-
return await inspectDocument(this.deps, input, scope);
|
|
50
|
-
}
|
|
51
|
-
async health(options = {}) {
|
|
52
|
-
const healthOptions = {
|
|
53
|
-
config: this.config,
|
|
54
|
-
providers: this.providers,
|
|
55
|
-
...(options.probeProcessBackends === undefined
|
|
56
|
-
? {}
|
|
57
|
-
: { probeProcessBackends: options.probeProcessBackends }),
|
|
58
|
-
};
|
|
59
|
-
return await documentHealth(healthOptions);
|
|
60
|
-
}
|
|
61
|
-
async capabilities(scope) {
|
|
62
|
-
const templates = scope === undefined
|
|
63
|
-
? await loadTemplateRegistry(undefined)
|
|
64
|
-
: await loadScopeTemplates(this.config, scope.workspaceRoot);
|
|
65
|
-
return documentCapabilities({
|
|
66
|
-
config: this.config,
|
|
67
|
-
providers: this.providers,
|
|
68
|
-
templates,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
/** Routes this runtime advertises, in documentation order. */
|
|
72
|
-
routes() {
|
|
73
|
-
return CONVERSION_ROUTES;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Retention sweep (§41). Meaningful only for a pinned storage root: with the
|
|
77
|
-
* default per-workspace layout the plugin cannot enumerate workspaces, and a
|
|
78
|
-
* sweep that guessed would delete other projects' artifacts.
|
|
79
|
-
*/
|
|
80
|
-
async cleanup(options = {}) {
|
|
81
|
-
if (!this.config.retention.enabled || this.config.storage.root === null)
|
|
82
|
-
return undefined;
|
|
83
|
-
const store = new ArtifactStore({ root: this.config.storage.root });
|
|
84
|
-
const removed = await store.cleanup({
|
|
85
|
-
maxAgeDays: this.config.retention.maxAgeDays,
|
|
86
|
-
...(options.now === undefined ? {} : { now: options.now }),
|
|
87
|
-
});
|
|
88
|
-
if (removed.removed.length > 0) {
|
|
89
|
-
this.deps.logger.info("documents.retention", {
|
|
90
|
-
removed: removed.removed.length,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return removed;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/** Build a runtime from raw (schema-parsed) configuration. */
|
|
97
|
-
export function createDocumentRuntime(options) {
|
|
98
|
-
const withEnv = applyDocumentsEnvOverrides(options.config, options.env ?? process.env);
|
|
99
|
-
const resolved = resolveDocumentsConfig(withEnv);
|
|
100
|
-
if (!resolved.enabled) {
|
|
101
|
-
throw new DocumentError("BACKEND_UNAVAILABLE", "the document subsystem is disabled in this deployment");
|
|
102
|
-
}
|
|
103
|
-
return new DocumentRuntime({
|
|
104
|
-
config: resolved,
|
|
105
|
-
...(options.logger === undefined ? {} : { logger: options.logger }),
|
|
106
|
-
...(options.seams === undefined ? {} : { seams: options.seams }),
|
|
107
|
-
...(options.providers === undefined
|
|
108
|
-
? {}
|
|
109
|
-
: { providers: options.providers }),
|
|
110
|
-
...(options.now === undefined ? {} : { now: options.now }),
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
export { resolveDocumentScope };
|
|
114
|
-
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/documents/runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* File-type identification and asset MIME policy (§26.3, §26.6, §17.1).
|
|
3
|
-
*
|
|
4
|
-
* The extension is a hint, never the authority: PDF is recognized by its
|
|
5
|
-
* header (after a bounded scan, because a PDF may carry leading junk), OOXML
|
|
6
|
-
* by its ZIP container plus the parts it holds, and macro-enabled documents by
|
|
7
|
-
* the presence of a VBA project. Legacy OLE documents (`.doc`, `.xls`, `.ppt`)
|
|
8
|
-
* are recognized only to be refused with a precise message.
|
|
9
|
-
*/
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { findZipEntry, readZipEntries, readZipEntry } from "../inspect/zip.js";
|
|
12
|
-
import { sanitizeBackendOutput } from "../errors.js";
|
|
13
|
-
const PDF_HEADER = Buffer.from("%PDF-", "latin1");
|
|
14
|
-
const ZIP_LOCAL_HEADER = Buffer.from([0x50, 0x4b, 0x03, 0x04]);
|
|
15
|
-
const ZIP_EMPTY_HEADER = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
|
|
16
|
-
const CFB_HEADER = Buffer.from([
|
|
17
|
-
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1,
|
|
18
|
-
]);
|
|
19
|
-
/** A PDF header may be preceded by junk; the spec fixes no bound, we use 4 KiB. */
|
|
20
|
-
const PDF_HEADER_SCAN_BYTES = 4 * 1024;
|
|
21
|
-
/** Bounded text sniffing window for Markdown/plain-text inputs. */
|
|
22
|
-
const TEXT_SNIFF_BYTES = 4 * 1024;
|
|
23
|
-
export const DOCUMENT_MEDIA_TYPES = {
|
|
24
|
-
md: "text/markdown",
|
|
25
|
-
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
26
|
-
pdf: "application/pdf",
|
|
27
|
-
};
|
|
28
|
-
export function mediaTypeFor(format) {
|
|
29
|
-
return DOCUMENT_MEDIA_TYPES[format];
|
|
30
|
-
}
|
|
31
|
-
export function extensionFor(format) {
|
|
32
|
-
return format === "md" ? "md" : format;
|
|
33
|
-
}
|
|
34
|
-
const DOCX_PART = /^word\/(?:document|styles|settings)\.xml$/iu;
|
|
35
|
-
const MACRO_PART = /^word\/vbaProject\.bin$/iu;
|
|
36
|
-
const CONTENT_TYPES_PART = "[Content_Types].xml";
|
|
37
|
-
const MACRO_CONTENT_TYPE = /macroEnabled/iu;
|
|
38
|
-
function sniffZip(buffer) {
|
|
39
|
-
const entries = readZipEntries(buffer);
|
|
40
|
-
if (entries === undefined) {
|
|
41
|
-
return { format: "unknown", mediaType: "application/octet-stream" };
|
|
42
|
-
}
|
|
43
|
-
const word = entries.some((entry) => DOCX_PART.test(entry.name));
|
|
44
|
-
const macroPart = entries.some((entry) => MACRO_PART.test(entry.name));
|
|
45
|
-
const contentTypes = findZipEntry(entries, CONTENT_TYPES_PART);
|
|
46
|
-
let macroContentType = false;
|
|
47
|
-
if (contentTypes !== undefined && !macroPart) {
|
|
48
|
-
const payload = readZipEntry(buffer, contentTypes);
|
|
49
|
-
if (payload !== undefined) {
|
|
50
|
-
macroContentType = MACRO_CONTENT_TYPE.test(payload.toString("utf8", 0, Math.min(payload.length, 8 * 1024)));
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (!word && !macroPart && !macroContentType) {
|
|
54
|
-
return {
|
|
55
|
-
format: "unknown",
|
|
56
|
-
mediaType: "application/zip",
|
|
57
|
-
unsupportedOffice: true,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const macroEnabled = macroPart || macroContentType;
|
|
61
|
-
return {
|
|
62
|
-
format: macroEnabled ? "docm" : "docx",
|
|
63
|
-
mediaType: macroEnabled
|
|
64
|
-
? "application/vnd.ms-word.document.macroEnabled.12"
|
|
65
|
-
: DOCUMENT_MEDIA_TYPES.docx,
|
|
66
|
-
wordprocessing: true,
|
|
67
|
-
macroEnabled,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/** Detect binary content without trusting the extension. */
|
|
71
|
-
function looksLikeText(buffer) {
|
|
72
|
-
const window = buffer.subarray(0, TEXT_SNIFF_BYTES);
|
|
73
|
-
for (const byte of window) {
|
|
74
|
-
if (byte === 0)
|
|
75
|
-
return false;
|
|
76
|
-
}
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
const MARKDOWN_EXTENSIONS = new Set([
|
|
80
|
-
".md",
|
|
81
|
-
".markdown",
|
|
82
|
-
".mdown",
|
|
83
|
-
".mkd",
|
|
84
|
-
".txt",
|
|
85
|
-
]);
|
|
86
|
-
export function detectFormatByExtension(filename) {
|
|
87
|
-
const extension = path.extname(filename).toLowerCase();
|
|
88
|
-
if (extension === ".pdf")
|
|
89
|
-
return "pdf";
|
|
90
|
-
if (extension === ".docx" || extension === ".docm")
|
|
91
|
-
return "docx";
|
|
92
|
-
if (MARKDOWN_EXTENSIONS.has(extension))
|
|
93
|
-
return "md";
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Identify a document from its bytes, falling back to the extension only where
|
|
98
|
-
* bytes are inconclusive (plain text and Markdown are both just text).
|
|
99
|
-
*/
|
|
100
|
-
export function sniffDocument(buffer, filename) {
|
|
101
|
-
const head = buffer.subarray(0, Math.max(PDF_HEADER_SCAN_BYTES, ZIP_LOCAL_HEADER.length));
|
|
102
|
-
if (head.includes(PDF_HEADER)) {
|
|
103
|
-
return { format: "pdf", mediaType: DOCUMENT_MEDIA_TYPES.pdf };
|
|
104
|
-
}
|
|
105
|
-
if (head.subarray(0, ZIP_LOCAL_HEADER.length).equals(ZIP_LOCAL_HEADER) ||
|
|
106
|
-
head.subarray(0, ZIP_EMPTY_HEADER.length).equals(ZIP_EMPTY_HEADER)) {
|
|
107
|
-
return sniffZip(buffer);
|
|
108
|
-
}
|
|
109
|
-
if (head.subarray(0, CFB_HEADER.length).equals(CFB_HEADER)) {
|
|
110
|
-
return { format: "unknown", mediaType: "application/x-ole-storage" };
|
|
111
|
-
}
|
|
112
|
-
const byExtension = filename === undefined ? undefined : detectFormatByExtension(filename);
|
|
113
|
-
if (byExtension === "md" && looksLikeText(buffer)) {
|
|
114
|
-
return { format: "markdown", mediaType: DOCUMENT_MEDIA_TYPES.md };
|
|
115
|
-
}
|
|
116
|
-
if (byExtension === "pdf" || byExtension === "docx") {
|
|
117
|
-
// The bytes contradict the name; the bytes win.
|
|
118
|
-
return { format: "unknown", mediaType: "application/octet-stream" };
|
|
119
|
-
}
|
|
120
|
-
if (looksLikeText(buffer)) {
|
|
121
|
-
return { format: "markdown", mediaType: DOCUMENT_MEDIA_TYPES.md };
|
|
122
|
-
}
|
|
123
|
-
return { format: "unknown", mediaType: "application/octet-stream" };
|
|
124
|
-
}
|
|
125
|
-
/** The supported source format behind a sniff result, or `undefined`. */
|
|
126
|
-
export function supportedFormatOf(sniffed) {
|
|
127
|
-
if (sniffed.format === "pdf")
|
|
128
|
-
return "pdf";
|
|
129
|
-
if (sniffed.format === "docx")
|
|
130
|
-
return "docx";
|
|
131
|
-
if (sniffed.format === "markdown")
|
|
132
|
-
return "md";
|
|
133
|
-
return undefined;
|
|
134
|
-
}
|
|
135
|
-
/** Human-facing explanation of a sniff result the pipeline refuses. */
|
|
136
|
-
export function describeUnsupported(sniffed, filename) {
|
|
137
|
-
if (sniffed.format === "docm") {
|
|
138
|
-
return `"${path.basename(filename)}" is a macro-enabled document; macro-enabled documents are not processed`;
|
|
139
|
-
}
|
|
140
|
-
if (sniffed.unsupportedOffice) {
|
|
141
|
-
return `"${path.basename(filename)}" is an OOXML package this pipeline does not support (supported: DOCX, PDF, Markdown)`;
|
|
142
|
-
}
|
|
143
|
-
if (sniffed.mediaType === "application/x-ole-storage") {
|
|
144
|
-
return `"${path.basename(filename)}" is a legacy OLE Office document (supported: DOCX, PDF, Markdown)`;
|
|
145
|
-
}
|
|
146
|
-
return `"${path.basename(filename)}" is not a supported document (supported: DOCX, PDF, Markdown)`;
|
|
147
|
-
}
|
|
148
|
-
export { DEFAULT_ASSET_MIME_TYPES, isAllowedAssetMimeType, mimeTypeForFilename, } from "./mime.js";
|
|
149
|
-
/** Magic-byte MIME detection for the asset types the pipeline accepts. */
|
|
150
|
-
export function mimeTypeOfBytes(buffer) {
|
|
151
|
-
if (buffer.length >= 8 &&
|
|
152
|
-
buffer
|
|
153
|
-
.subarray(0, 8)
|
|
154
|
-
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
|
|
155
|
-
return "image/png";
|
|
156
|
-
}
|
|
157
|
-
if (buffer.length >= 3 &&
|
|
158
|
-
buffer[0] === 0xff &&
|
|
159
|
-
buffer[1] === 0xd8 &&
|
|
160
|
-
buffer[2] === 0xff) {
|
|
161
|
-
return "image/jpeg";
|
|
162
|
-
}
|
|
163
|
-
if (buffer.length >= 6 &&
|
|
164
|
-
buffer.toString("latin1", 0, 6).startsWith("GIF8")) {
|
|
165
|
-
return "image/gif";
|
|
166
|
-
}
|
|
167
|
-
if (buffer.length >= 12 &&
|
|
168
|
-
buffer.toString("latin1", 0, 4) === "RIFF" &&
|
|
169
|
-
buffer.toString("latin1", 8, 12) === "WEBP") {
|
|
170
|
-
return "image/webp";
|
|
171
|
-
}
|
|
172
|
-
if (buffer.length >= 2 && buffer.toString("latin1", 0, 2) === "BM") {
|
|
173
|
-
return "image/bmp";
|
|
174
|
-
}
|
|
175
|
-
if (buffer.length >= 4) {
|
|
176
|
-
const little = buffer.toString("latin1", 0, 4);
|
|
177
|
-
if (little === "II*\u0000" || little === "MM\u0000*")
|
|
178
|
-
return "image/tiff";
|
|
179
|
-
}
|
|
180
|
-
return undefined;
|
|
181
|
-
}
|
|
182
|
-
/** A short, sanitized description of the first bytes, for error messages. */
|
|
183
|
-
export function describeBytes(buffer) {
|
|
184
|
-
return sanitizeBackendOutput([...buffer.subarray(0, 16)]
|
|
185
|
-
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
186
|
-
.join(" "), 120);
|
|
187
|
-
}
|
|
188
|
-
//# sourceMappingURL=file-types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"file-types.js","sourceRoot":"","sources":["../../../src/documents/security/file-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAClD,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAC/D,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAC/D,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC7B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC/C,CAAC,CAAC;AACH,mFAAmF;AACnF,MAAM,qBAAqB,GAAG,CAAC,GAAG,IAAI,CAAC;AACvC,mEAAmE;AACnE,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,CAAC;AAElC,MAAM,CAAC,MAAM,oBAAoB,GAA6C;IAC5E,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,yEAAyE;IAC/E,GAAG,EAAE,iBAAiB;CACvB,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAsB;IACjD,OAAO,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACzC,CAAC;AAaD,MAAM,SAAS,GAAG,6CAA6C,CAAC;AAChE,MAAM,UAAU,GAAG,2BAA2B,CAAC;AAC/C,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AACjD,MAAM,kBAAkB,GAAG,gBAAgB,CAAC;AAE5C,SAAS,QAAQ,CAAC,MAAc;IAC9B,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC;IACtE,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;IAC/D,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,YAAY,KAAK,SAAS,IAAI,CAAC,SAAS,EAAE,CAAC;QAC7C,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACnD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,CACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAChE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC7C,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,iBAAiB;YAC5B,iBAAiB,EAAE,IAAI;SACxB,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,SAAS,IAAI,gBAAgB,CAAC;IACnD,OAAO;QACL,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACtC,SAAS,EAAE,YAAY;YACrB,CAAC,CAAC,kDAAkD;YACpD,CAAC,CAAC,oBAAoB,CAAC,IAAI;QAC7B,cAAc,EAAE,IAAI;QACpB,YAAY;KACb,CAAC;AACJ,CAAC;AAED,4DAA4D;AAC5D,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACpD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,KAAK;IACL,WAAW;IACX,QAAQ;IACR,MAAM;IACN,MAAM;CACP,CAAC,CAAC;AAEH,MAAM,UAAU,uBAAuB,CACrC,QAAgB;IAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACvD,IAAI,SAAS,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IAClE,IAAI,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAc,EACd,QAAiB;IAEjB,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAC1B,CAAC,EACD,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,gBAAgB,CAAC,MAAM,CAAC,CACzD,CAAC;IACF,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,oBAAoB,CAAC,GAAG,EAAE,CAAC;IAChE,CAAC;IACD,IACE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC;QAClE,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAClE,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC;IACvE,CAAC;IACD,MAAM,WAAW,GACf,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IACzE,IAAI,WAAW,KAAK,IAAI,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,oBAAoB,CAAC,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,IAAI,WAAW,KAAK,KAAK,IAAI,WAAW,KAAK,MAAM,EAAE,CAAC;QACpD,gDAAgD;QAChD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC;IACtE,CAAC;IACD,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,oBAAoB,CAAC,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,0BAA0B,EAAE,CAAC;AACtE,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,iBAAiB,CAC/B,OAAwB;IAExB,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IAC7C,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,mBAAmB,CACjC,OAAwB,EACxB,QAAgB;IAEhB,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,0EAA0E,CAAC;IAC/G,CAAC;IACD,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAC9B,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,uFAAuF,CAAC;IAC5H,CAAC;IACD,IAAI,OAAO,CAAC,SAAS,KAAK,2BAA2B,EAAE,CAAC;QACtD,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,oEAAoE,CAAC;IACzG,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,gEAAgE,CAAC;AACrG,CAAC;AAED,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,WAAW,CAAC;AAEnB,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,IACE,MAAM,CAAC,MAAM,IAAI,CAAC;QAClB,MAAM;aACH,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;aACd,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EACxE,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IACE,MAAM,CAAC,MAAM,IAAI,CAAC;QAClB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;QAClB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;QAClB,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAClB,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IACE,MAAM,CAAC,MAAM,IAAI,CAAC;QAClB,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAClD,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IACE,MAAM,CAAC,MAAM,IAAI,EAAE;QACnB,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM;QAC1C,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,MAAM,EAC3C,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACnE,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,IAAI,MAAM,KAAK,WAAW,IAAI,MAAM,KAAK,WAAW;YAAE,OAAO,YAAY,CAAC;IAC5E,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,OAAO,qBAAqB,CAC1B,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;SACxB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SACjD,IAAI,CAAC,GAAG,CAAC,EACZ,GAAG,CACJ,CAAC;AACJ,CAAC"}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resource limits and concurrency control (§26.4, §27).
|
|
3
|
-
*
|
|
4
|
-
* Every expensive stage (render, extraction, OCR) runs behind a semaphore so a
|
|
5
|
-
* burst of documents cannot exhaust the host, and every size/count budget is
|
|
6
|
-
* checked before the work starts rather than after a backend has already spent
|
|
7
|
-
* minutes on it.
|
|
8
|
-
*/
|
|
9
|
-
import { DocumentError } from "../errors.js";
|
|
10
|
-
export function assertBytesWithinBudget(bytes, maxBytes, label) {
|
|
11
|
-
if (bytes > maxBytes) {
|
|
12
|
-
throw new DocumentError("INPUT_TOO_LARGE", `${label} is ${bytes} bytes; the configured limit is ${maxBytes}`, { details: { bytes, maxBytes } });
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export function assertCharsWithinBudget(chars, maxChars, label) {
|
|
16
|
-
if (chars > maxChars) {
|
|
17
|
-
throw new DocumentError("DOCUMENT_TOO_LARGE", `${label} is ${chars} characters; the configured limit is ${maxChars}`, { details: { chars, maxChars } });
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export function assertCountWithinBudget(count, maxCount, label) {
|
|
21
|
-
if (count > maxCount) {
|
|
22
|
-
throw new DocumentError("DOCUMENT_TOO_LARGE", `${label} is ${count}; the configured limit is ${maxCount}`, { details: { count, maxCount } });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Counting semaphore with FIFO fairness. An aborted waiter leaves the queue
|
|
27
|
-
* without consuming a slot, so a stopped turn never leaks capacity.
|
|
28
|
-
*/
|
|
29
|
-
export function createSemaphore(limit) {
|
|
30
|
-
const max = Math.max(1, Math.floor(limit));
|
|
31
|
-
let inUse = 0;
|
|
32
|
-
const waiters = [];
|
|
33
|
-
const releaseOnce = () => {
|
|
34
|
-
let released = false;
|
|
35
|
-
return () => {
|
|
36
|
-
if (released)
|
|
37
|
-
return;
|
|
38
|
-
released = true;
|
|
39
|
-
inUse -= 1;
|
|
40
|
-
const next = waiters.shift();
|
|
41
|
-
if (next !== undefined) {
|
|
42
|
-
inUse += 1;
|
|
43
|
-
next.signal?.removeEventListener("abort", next.reject);
|
|
44
|
-
next.resolve(releaseOnce());
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
return {
|
|
49
|
-
limit: max,
|
|
50
|
-
get inUse() {
|
|
51
|
-
return inUse;
|
|
52
|
-
},
|
|
53
|
-
async acquire(signal) {
|
|
54
|
-
if (signal?.aborted === true) {
|
|
55
|
-
throw new DocumentError("INVALID_INPUT", "the operation was cancelled");
|
|
56
|
-
}
|
|
57
|
-
if (inUse < max) {
|
|
58
|
-
inUse += 1;
|
|
59
|
-
return releaseOnce();
|
|
60
|
-
}
|
|
61
|
-
return await new Promise((resolve, reject) => {
|
|
62
|
-
const waiter = {
|
|
63
|
-
resolve,
|
|
64
|
-
reject,
|
|
65
|
-
...(signal === undefined ? {} : { signal }),
|
|
66
|
-
};
|
|
67
|
-
waiters.push(waiter);
|
|
68
|
-
signal?.addEventListener("abort", () => {
|
|
69
|
-
const index = waiters.indexOf(waiter);
|
|
70
|
-
if (index >= 0)
|
|
71
|
-
waiters.splice(index, 1);
|
|
72
|
-
reject(new DocumentError("INVALID_INPUT", "the operation was cancelled"));
|
|
73
|
-
}, { once: true });
|
|
74
|
-
});
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
//# sourceMappingURL=limits.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"limits.js","sourceRoot":"","sources":["../../../src/documents/security/limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MIME policy for document assets (§17.1).
|
|
3
|
-
*
|
|
4
|
-
* Kept free of Node builtins on purpose: the QA settings schema reaches this
|
|
5
|
-
* module from the browser bundle, so anything imported here also has to run in
|
|
6
|
-
* a page. The byte sniffing stays with the pipeline's file-type module, which
|
|
7
|
-
* may import whatever it needs.
|
|
8
|
-
*/
|
|
9
|
-
/** Asset MIME types accepted by default. */
|
|
10
|
-
export const DEFAULT_ASSET_MIME_TYPES = [
|
|
11
|
-
"image/png",
|
|
12
|
-
"image/jpeg",
|
|
13
|
-
"image/gif",
|
|
14
|
-
"image/webp",
|
|
15
|
-
"image/bmp",
|
|
16
|
-
"image/tiff",
|
|
17
|
-
];
|
|
18
|
-
const MIME_BY_EXTENSION = {
|
|
19
|
-
".png": "image/png",
|
|
20
|
-
".jpg": "image/jpeg",
|
|
21
|
-
".jpeg": "image/jpeg",
|
|
22
|
-
".gif": "image/gif",
|
|
23
|
-
".webp": "image/webp",
|
|
24
|
-
".bmp": "image/bmp",
|
|
25
|
-
".tif": "image/tiff",
|
|
26
|
-
".tiff": "image/tiff",
|
|
27
|
-
".svg": "image/svg+xml",
|
|
28
|
-
};
|
|
29
|
-
/** Lowercased extension of a file name, including the dot. */
|
|
30
|
-
function extensionOf(filename) {
|
|
31
|
-
const separator = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\"));
|
|
32
|
-
const base = separator < 0 ? filename : filename.slice(separator + 1);
|
|
33
|
-
const dot = base.lastIndexOf(".");
|
|
34
|
-
return dot <= 0 ? "" : base.slice(dot).toLowerCase();
|
|
35
|
-
}
|
|
36
|
-
export function mimeTypeForFilename(filename) {
|
|
37
|
-
return MIME_BY_EXTENSION[extensionOf(filename)];
|
|
38
|
-
}
|
|
39
|
-
export function isAllowedAssetMimeType(mimeType, allowed) {
|
|
40
|
-
const normalized = mimeType.trim().toLowerCase();
|
|
41
|
-
return allowed.some((entry) => entry.trim().toLowerCase() === normalized);
|
|
42
|
-
}
|
|
43
|
-
//# sourceMappingURL=mime.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mime.js","sourceRoot":"","sources":["../../../src/documents/security/mime.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4CAA4C;AAC5C,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;CACb,CAAC;AAEF,MAAM,iBAAiB,GAAqC;IAC1D,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,eAAe;CACxB,CAAC;AAEF,8DAA8D;AAC9D,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,EACzB,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAC3B,CAAC;IACF,MAAM,IAAI,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;IACtE,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAO,iBAAiB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,OAA0B;IAE1B,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;AAC5E,CAAC"}
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Path containment and filename hygiene (§26.2, §32).
|
|
3
|
-
*
|
|
4
|
-
* Two rules hold everywhere in the pipeline:
|
|
5
|
-
*
|
|
6
|
-
* - every path the pipeline touches is resolved against an allowed root and
|
|
7
|
-
* the resolution must stay inside it — traversal, absolute escapes and
|
|
8
|
-
* `file://` references are refused before anything is opened;
|
|
9
|
-
* - a caller-supplied filename is a label, never a path: directories are
|
|
10
|
-
* dropped, separators and reserved characters collapse to `-`, and the
|
|
11
|
-
* extension is the one the operation itself chose.
|
|
12
|
-
*/
|
|
13
|
-
import { realpath } from "node:fs/promises";
|
|
14
|
-
import path from "node:path";
|
|
15
|
-
import { pathToFileURL } from "node:url";
|
|
16
|
-
import { DocumentError } from "../errors.js";
|
|
17
|
-
/** Whether `target` is `root` or a descendant of it (no symlink resolution). */
|
|
18
|
-
export function isInsideRoot(root, target) {
|
|
19
|
-
const relative = path.relative(root, target);
|
|
20
|
-
return (relative === "" ||
|
|
21
|
-
(!relative.startsWith(`..${path.sep}`) &&
|
|
22
|
-
relative !== ".." &&
|
|
23
|
-
!path.isAbsolute(relative)));
|
|
24
|
-
}
|
|
25
|
-
export function assertInsideRoot(root, target, label) {
|
|
26
|
-
const resolvedRoot = path.resolve(root);
|
|
27
|
-
const resolvedTarget = path.resolve(target);
|
|
28
|
-
if (!isInsideRoot(resolvedRoot, resolvedTarget)) {
|
|
29
|
-
throw new DocumentError("PATH_NOT_ALLOWED", `${label} is outside the allowed document scope`, { details: { label } });
|
|
30
|
-
}
|
|
31
|
-
return resolvedTarget;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Canonicalize a path for containment checks: the existing prefix is resolved
|
|
35
|
-
* through symlinks, the non-existent remainder is appended unresolved. A
|
|
36
|
-
* symlink pointing outside the root therefore canonicalizes outside it.
|
|
37
|
-
*/
|
|
38
|
-
export async function canonicalizeForContainment(input) {
|
|
39
|
-
const resolved = path.resolve(input);
|
|
40
|
-
let current = resolved;
|
|
41
|
-
const remainder = [];
|
|
42
|
-
for (;;) {
|
|
43
|
-
try {
|
|
44
|
-
const canonical = await realpath(current);
|
|
45
|
-
return remainder.length === 0
|
|
46
|
-
? canonical
|
|
47
|
-
: path.join(canonical, ...remainder.reverse());
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
const parent = path.dirname(current);
|
|
51
|
-
if (parent === current)
|
|
52
|
-
return resolved;
|
|
53
|
-
remainder.push(path.basename(current));
|
|
54
|
-
current = parent;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
/** Resolve a caller-supplied path against `root`, refusing any escape. */
|
|
59
|
-
export async function resolveInsideRoot(root, requested, label) {
|
|
60
|
-
if (requested.trim() === "") {
|
|
61
|
-
throw new DocumentError("INVALID_INPUT", `${label} must be a non-empty path`);
|
|
62
|
-
}
|
|
63
|
-
if (requested.toLowerCase().startsWith("file:")) {
|
|
64
|
-
throw new DocumentError("PATH_NOT_ALLOWED", `${label} must be a filesystem path, not a file URL`);
|
|
65
|
-
}
|
|
66
|
-
const canonicalRoot = await canonicalizeForContainment(root);
|
|
67
|
-
const target = path.resolve(canonicalRoot, requested);
|
|
68
|
-
const canonicalTarget = await canonicalizeForContainment(target);
|
|
69
|
-
assertInsideRoot(canonicalRoot, canonicalTarget, label);
|
|
70
|
-
return canonicalTarget;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Turn a caller-supplied filename into a safe file name (§32).
|
|
74
|
-
* `../../foo report?.docx` becomes `foo-report.docx`.
|
|
75
|
-
*/
|
|
76
|
-
export function sanitizeFilename(requested, fallbackStem, extension) {
|
|
77
|
-
const suffix = extension === ""
|
|
78
|
-
? ""
|
|
79
|
-
: extension.startsWith(".")
|
|
80
|
-
? extension
|
|
81
|
-
: `.${extension}`;
|
|
82
|
-
const source = (requested ?? "").trim();
|
|
83
|
-
let stem = "";
|
|
84
|
-
if (source !== "") {
|
|
85
|
-
// A Windows-style separator survives `path.basename` on POSIX, so both are
|
|
86
|
-
// cut explicitly before any further normalization.
|
|
87
|
-
const basename = source.split(/[\\/]+/u).pop() ?? "";
|
|
88
|
-
const withoutExtension = basename.replace(/\.[A-Za-z0-9]{1,8}$/u, "");
|
|
89
|
-
stem = withoutExtension
|
|
90
|
-
.normalize("NFC")
|
|
91
|
-
/* eslint-disable-next-line no-control-regex -- control characters are the point */
|
|
92
|
-
.replace(/[\u0000-\u001F\u007F]/gu, "")
|
|
93
|
-
.replace(/[<>:"|?*]+/gu, "")
|
|
94
|
-
.replace(/[\s._]+/gu, "-")
|
|
95
|
-
.replace(/-{2,}/gu, "-")
|
|
96
|
-
.replace(/^[-.]+|[-.]+$/gu, "");
|
|
97
|
-
}
|
|
98
|
-
const safeStem = stem === "" ? fallbackStem : stem.slice(0, 80);
|
|
99
|
-
return `${safeStem}${suffix}`;
|
|
100
|
-
}
|
|
101
|
-
/** `file:///...` form required by `-env:UserInstallation` and friends. */
|
|
102
|
-
export function toFileUri(target) {
|
|
103
|
-
return pathToFileURL(path.resolve(target)).href;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Assert an asset reference inside Markdown targets the assets directory and
|
|
107
|
-
* nothing else: no absolute paths, no URLs, no traversal (§17.1).
|
|
108
|
-
*/
|
|
109
|
-
export function assertRelativeAssetReference(reference) {
|
|
110
|
-
const trimmed = reference.trim();
|
|
111
|
-
if (trimmed === "") {
|
|
112
|
-
throw new DocumentError("INVALID_ASSET", "asset reference is empty");
|
|
113
|
-
}
|
|
114
|
-
if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//u.test(trimmed) ||
|
|
115
|
-
trimmed.startsWith("//") ||
|
|
116
|
-
trimmed.startsWith("\\\\") ||
|
|
117
|
-
/^(?:data|file|javascript):/iu.test(trimmed)) {
|
|
118
|
-
throw new DocumentError("INVALID_ASSET", `asset reference must be relative to the artifact assets directory (${trimmed})`);
|
|
119
|
-
}
|
|
120
|
-
const normalized = trimmed.replace(/\\/gu, "/");
|
|
121
|
-
if (normalized.startsWith("/") || normalized.split("/").includes("..")) {
|
|
122
|
-
throw new DocumentError("INVALID_ASSET", `asset reference must not leave the assets directory (${trimmed})`);
|
|
123
|
-
}
|
|
124
|
-
return normalized;
|
|
125
|
-
}
|
|
126
|
-
/** Recursively-size snapshot helper used by the limits guard. */
|
|
127
|
-
export function assertNotBlank(value, label) {
|
|
128
|
-
if (value.trim() === "") {
|
|
129
|
-
throw new DocumentError("INVALID_INPUT", `${label} must not be blank`);
|
|
130
|
-
}
|
|
131
|
-
return value;
|
|
132
|
-
}
|
|
133
|
-
//# sourceMappingURL=paths.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/documents/security/paths.ts"],"names":[],"mappings":"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"}
|