Reuse preview sanitizer across client page bundles
This commit is contained in:
1 parent
646814d6df
commit
a023049431
4 files changed
+20
-5
No files matched your search
@@ -272,7 +272,7 @@
|
|||||||
},
|
},
|
||||||
"packages/block-editor": {
|
"packages/block-editor": {
|
||||||
"name": "@wrnexus/block-editor",
|
"name": "@wrnexus/block-editor",
|
||||||
"version": "0.1.19",
|
"version": "0.1.20",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-xml": "6.1.0",
|
"@codemirror/lang-xml": "6.1.0",
|
||||||
"@codemirror/language": "6.12.4",
|
"@codemirror/language": "6.12.4",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/block-editor",
|
"name": "@wrnexus/block-editor",
|
||||||
"version": "0.1.19",
|
"version": "0.1.20",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "Hydrated accessible editor runtime for WRNexus block documents.",
|
"description": "Hydrated accessible editor runtime for WRNexus block documents.",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import createDOMPurify from "dompurify";
|
import createDOMPurify from "dompurify";
|
||||||
|
|
||||||
const sanitizers = new WeakMap<object, ReturnType<typeof createDOMPurify>>();
|
// Page modules are bundled separately. Keep the sanitizer on the realm so SPA
|
||||||
|
// navigation reuses its Trusted Types policy instead of creating it twice.
|
||||||
|
const sanitizerKey = Symbol.for("wrnexus.block-editor.preview-sanitizer");
|
||||||
|
type PreviewRealm = Window & { [sanitizerKey]?: ReturnType<typeof createDOMPurify> };
|
||||||
/** Sanitize generated previews in the sink's realm, including Trusted Types. */
|
/** Sanitize generated previews in the sink's realm, including Trusted Types. */
|
||||||
export function builderPreviewHTML(html: string, doc: Document = document): string {
|
export function builderPreviewHTML(html: string, doc: Document = document): string {
|
||||||
const realm = doc.defaultView;
|
const realm = doc.defaultView;
|
||||||
if (!realm) throw new Error("Preview document has no browser realm");
|
if (!realm) throw new Error("Preview document has no browser realm");
|
||||||
let sanitizer = sanitizers.get(realm);
|
let sanitizer = (realm as PreviewRealm)[sanitizerKey];
|
||||||
if (!sanitizer) {
|
if (!sanitizer) {
|
||||||
sanitizer = createDOMPurify(realm);
|
sanitizer = createDOMPurify(realm);
|
||||||
sanitizers.set(realm, sanitizer);
|
Object.defineProperty(realm, sanitizerKey, { value: sanitizer });
|
||||||
}
|
}
|
||||||
return sanitizer.sanitize(html, {
|
return sanitizer.sanitize(html, {
|
||||||
WHOLE_DOCUMENT: true,
|
WHOLE_DOCUMENT: true,
|
||||||
|
|||||||
@@ -11,3 +11,15 @@ test("preview sanitization preserves email layout and editor markers but removes
|
|||||||
expect(result).not.toMatch(/onerror|javascript:|<script|<iframe/);
|
expect(result).not.toMatch(/onerror|javascript:|<script|<iframe/);
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("separately bundled preview modules reuse one realm sanitizer", async () => {
|
||||||
|
const { window } = new JSDOM("");
|
||||||
|
const doc = window.document as unknown as Document;
|
||||||
|
builderPreviewHTML("<p>First page</p>", doc);
|
||||||
|
const key = Symbol.for("wrnexus.block-editor.preview-sanitizer");
|
||||||
|
const first = (window as any)[key];
|
||||||
|
const secondModule = await import("../src/preview-html.ts?second-page");
|
||||||
|
expect(String(secondModule.builderPreviewHTML("<p>Second page</p>", doc))).toContain("Second page");
|
||||||
|
expect((window as any)[key]).toBe(first);
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user