Content-Security-Policy
The package works under a strict Content-Security-Policy. What script-src must allow depends on
the entry point; styles need nothing special.
| You use | script-src needs |
Why |
|---|---|---|
@tinyactors/scxmljs (sandboxed), or <scxml-view> without trusted |
'wasm-unsafe-eval' |
QuickJS is WebAssembly, compiled at run time |
@tinyactors/scxmljs/trusted, or <scxml-view trusted> |
'unsafe-eval' |
chart code runs with eval in a hidden iframe |
only <scxml-explorer> with a session you created |
whatever that session's entry point needs | the explorer itself evaluates nothing |
'wasm-unsafe-eval' only allows compiling WebAssembly; it doesn't allow eval() of JavaScript.
It's the smaller permission, which is one more reason to prefer the sandbox.
A policy for a page that uses <scxml-view> with sandboxed charts, served from the same origin:
Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'And one that also runs trusted sessions:
Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval' 'unsafe-eval'; style-src 'self'Both are tested in CI in Chromium, Firefox and WebKit (tests/browser/specs/csp.pw.ts, with
these exact policies plus the import map's hash): under the first, sandboxed <scxml-view> and
<scxml-explorer> work with no violations and a trusted <scxml-view> is refused (its eval
is the only violation); under the second, everything works with no violations. The same two
checks run against the classic-script (IIFE) bundles from Bundling.
The other directives#
- Styles.
style-src 'self'is enough;'unsafe-inline'isn't needed. The elements style themselves with constructable stylesheets adopted by their shadow roots, and position things through the CSSOM (element.style), neither of whichstyle-srcrestricts. They never writestyleattributes or inline<style>elements. If you linkthemes/tinyactors.cssfrom another origin, allow that origin. - Fetching charts.
<scxml-view src>, and the loader it uses for<script src>,<data src>and<invoke src>, usefetch(): the URLs must be allowed byconnect-src(default-src 'self'covers same-origin charts). Your own I/O processors need whatever their transport needs. - Frames. The trusted data model creates a same-origin
about:blankiframe, whichframe-srcdoesn't block. - Nothing else. No fonts, images, workers or
.wasmfiles are loaded: QuickJS is embedded in the JavaScript. - Import maps are inline scripts. If you load the package through an
import map, allow it with a hash
(
'sha256-…'of the map's text) or a nonce inscript-src, and allow the CDN's origin.
Trusted Types#
With require-trusted-types-for 'script', the browser refuses strings where it expects HTML or
scripts:
- The elements build all their DOM with
createElementand never parse HTML, so they work unchanged. - Parsing SCXML text uses
DOMParser.parseFromString, which then needsTrustedHTML. Pass adomParserthat wraps the text with your own policy. It goes intocreateSession(), or into<scxml-view>'soptions(set it beforesrc):
import { createSession } from "@tinyactors/scxmljs";
// the Trusted Types API (types: @types/trusted-types)
declare const trustedTypes: { createPolicy(name: string, rules: { createHTML(s: string): string }): { createHTML(s: string): string } };
const policy = trustedTypes.createPolicy("scxml", { createHTML: (text) => text });
const domParser = {
parseFromString: (text: string, type: string) => new DOMParser().parseFromString(policy.createHTML(text), type as DOMParserSupportedType),
};
const session = await createSession(await (await fetch("chart.scxml")).text(), { domParser });
document.querySelector("scxml-view")!.options = { domParser }; If your policy also uses trusted-types <names>, include your policy's name.
- The trusted data model evaluates chart code with
eval, which Trusted Types blocks (it would needTrustedScript). Use the sandboxed entry point on such pages.
Tested in CI in Chromium, Firefox and WebKit, which all enforce Trusted Types: a sandboxed
<scxml-view> with this domParser and <scxml-explorer> (with a screenshot of its focus pane),
no violations and no errors.