import { describe, expect, it } from "vitest"; import { parseSvgSource } from "../../src/document/source-parser"; import { createEditingProjection, createSanitizedCandidate, inspectSvgSecurity, } from "../../src/security/sanitize-svg"; function parse(source: string) { const result = parseSvgSource(source, 1); expect(result.semantic).not.toBeNull(); return result.semantic!; } describe("hostile SVG editing projection", () => { it("preserves active content in canonical source but removes it from projection", () => { const semantic = parse(`
HTML
`); const findings = inspectSvgSecurity(semantic); const codes = findings.map((item) => item.code); expect(codes).toEqual( expect.arrayContaining([ "event-handler", "blocked-script", "blocked-foreignobject", "unsafe-url", ]), ); expect(codes.some((code) => code.startsWith("unsafe-inline-css"))).toBe( true, ); expect(semantic.source).toContain("steal()"); const projection = createEditingProjection(semantic); expect(projection.source).not.toMatch( / { const semantic = parse( ``, ); const projection = createEditingProjection(semantic); expect(projection.source).toContain("url(#p)"); expect(projection.source).toContain("data:image/png;base64"); }); it("removes internal mapping metadata from explicit sanitized source", () => { const semantic = parse( '', ); const candidate = createSanitizedCandidate(semantic); expect(candidate.source).not.toContain("data-svg-tools-node"); expect(candidate.source).toContain('id="c"'); }); it("parses CSS and removes imports, external URLs and behavior-like properties", () => { const semantic = parse(` `); const findings = inspectSvgSecurity(semantic); expect( findings.some((item) => item.code.startsWith("unsafe-stylesheet")), ).toBe(true); expect( findings.some((item) => item.code.startsWith("unsafe-inline-css")), ).toBe(true); const projection = createEditingProjection(semantic); expect(projection.source).not.toContain("evil.example"); expect(projection.source).not.toContain("-moz-binding"); }); it("blocks CSS resource functions even when a URL is represented as a string", () => { const semantic = parse( '', ); const findings = inspectSvgSecurity(semantic); expect(findings).toContainEqual( expect.objectContaining({ code: "unsafe-stylesheet", description: expect.stringContaining("image-set()"), }), ); expect(createEditingProjection(semantic).source).not.toContain( "tracker.png", ); }); it("allows only references that resolve to one unique local ID", () => { const semantic = parse(` `); const projection = createEditingProjection(semantic).source; const document = new DOMParser().parseFromString( projection, "image/svg+xml", ); expect(document.getElementById("ok")?.getAttribute("fill")).toBe( "url(#unique)", ); expect(document.getElementById("missing")?.hasAttribute("fill")).toBe( false, ); expect(document.getElementById("ambiguous")?.hasAttribute("fill")).toBe( false, ); }); it("keeps the normal canvas static by removing declarative animation elements", () => { const semantic = parse(` `); const findings = inspectSvgSecurity(semantic); expect(findings.map((item) => item.code)).toEqual( expect.arrayContaining(["blocked-animate", "blocked-set"]), ); const projection = createEditingProjection(semantic).source; expect(projection).not.toMatch(/ { const semantic = parse(` `); expect(inspectSvgSecurity(semantic)).toContainEqual( expect.objectContaining({ code: "unknown-namespace", editingProjectionAction: "removed", }), ); expect(createEditingProjection(semantic).source).not.toContain("widget"); }); });