Files
av-tools/docs/PORTAL_REQUIREMENTS.md

4.3 KiB

Toolbox Portal requirements

av-tools is built and packaged independently. Toolbox Portal consumes the exact ZIP and SHA-256 from a reviewed release lock; it must never import the app source into its React build.

Required serving behavior

All app, wrapper, core, WASM and worker responses are same-origin and served over HTTPS (or trusted localhost). Apply:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
X-Content-Type-Options: nosniff

Serve .wasm as application/wasm, JavaScript modules as a JavaScript MIME type and JSON as application/json. Test real responses under /apps/av/vendor/ffmpeg/0.12.10/...; a file-extension allowlist alone does not prove the MIME type.

Suggested CSP:

default-src 'self';
script-src 'self' 'wasm-unsafe-eval';
worker-src 'self' blob:;
connect-src 'self';
img-src 'self' blob: data:;
media-src 'self' blob:;
font-src 'self';
style-src 'self';
object-src 'none';
frame-src 'none';
frame-ancestors 'none';
base-uri 'none';
form-action 'none';

'wasm-unsafe-eval' is the narrow WebAssembly permission; broad 'unsafe-eval' is unnecessary. worker-src blob: covers the wrapper-created worker path. media-src blob: permits local source/result previews.

Immutable reference and active-worktree state

Portal revision bda9da044d61c109afd9969d357cc27f76648938 already sends COOP same-origin, COEP require-corp, CORP same-origin, script-src 'self' 'wasm-unsafe-eval', and worker-src 'self' blob:. Its packaged nginx CSP does not declare media-src; default-src 'self' therefore blocks local blob: audio/video URLs. The expected browser diagnostic is equivalent to:

Refused to load media from 'blob:…' because it violates
"default-src 'self'".

Smallest required Portal change: append exactly media-src 'self' blob:; to that CSP. This permits only same-origin and in-memory Blob media; it does not permit remote media hosts, inline script or eval. If the Portal is not changed, conversion/download can remain available but Blob source/result preview must show a clear disabled reason.

As inspected on 2026-07-24, the active /mnt/DATA/git/toolbox-portal/deploy/nginx.conf contains that exact directive as a local worktree patch. The worktree still resolves to the immutable revision above, so the patch is useful for local deployment testing but is not a committed Portal revision and must not be cited as published release evidence. The clean-reference assembly smoke therefore continues to require --allow-known-header-gap until a reviewed Portal commit contains the fix.

The nginx profile includes .wasm in its static allowlist/gzip types but relies on the base image mime.types. Verify Content-Type: application/wasm against the pinned image; add an explicit mapping if the response differs.

Caching

The immutable Portal reference's cache map makes Vite content-hashed assets immutable but leaves versioned FFmpeg cores at no-cache. Correctness is unaffected. For performance, the exact directory apps/av/vendor/ffmpeg/0.12.10/{st,mt}/ may receive:

Cache-Control: public, max-age=31536000, immutable

Only do this while a version path is immutable and verified against version.json. Keep index.html, manifest/catalog/release JSON and legal notices revalidated.

Nested path and context

The artifact uses base: './', entry: './', a relative icon, a relative manifest URL and relative core URLs. Portal may therefore target av, yielding apps/av/. Do not rewrite files to root-absolute /assets or /vendor. Use top-level navigation; embedding is unsupported.

The app remains usable without valid Toolbox context. It validates context version/origin and falls back to standalone shell behavior without moving or duplicating suite controls.

Fallback contract

MT requires all isolation headers plus secure context and SharedArrayBuffer. When any prerequisite or MT load fails, the app terminates that instance and loads ST. The manifest intentionally declares crossOriginIsolated: false because isolation is not an unconditional requirement; it declares workers, secure context, IndexedDB and top-level context.

See scripts/portal-assembly-smoke.mjs and docs/RELEASE.md for the temporary, non-mutating assembly procedure.