Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687// src/node/server.ts: the header policy scripts/serve.mjs serves the repo with and the// package ships as @nibling/kernel/server. Runs in Node; no page.import { test, expect } from "@playwright/test";import { contentSecurityPolicy, headersFor, nibHeaders } from "../src/node/server";
const ISOLATED = { "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp", "Cross-Origin-Resource-Policy": "same-origin",};
test("headersFor() isolates every path by default and leaves CSP and Service-Worker-Allowed to options", () => { expect(headersFor("/index.html")).toEqual(ISOLATED); expect(headersFor("/plain.html", { isolate: (p) => p !== "/plain.html", resourcePolicy: false })).toEqual({}); expect(headersFor("/nib/sw.js", { csp: (p) => p.endsWith(".js") && contentSecurityPolicy(), serviceWorkerAllowed: (p) => p === "/nib/sw.js", })).toEqual({ ...ISOLATED, "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self'; worker-src 'self'; connect-src 'self' data: blob:", "Service-Worker-Allowed": "/", }); expect(contentSecurityPolicy({ inlineScripts: true, inlineStyles: true })).toBe( "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; worker-src 'self'; connect-src 'self' data: blob:", ); // The registry is opt-in: true names npm's, a string names another origin. expect(contentSecurityPolicy({ registry: true })).toMatch(/; connect-src 'self' data: blob: https:\/\/registry\.npmjs\.org$/); expect(contentSecurityPolicy({ registry: "https://npm.example.test" })).toMatch(/; connect-src 'self' data: blob: https:\/\/npm\.example\.test$/);});
test("contentSecurityPolicy() lets a coordinator frame sandbox origins and a sandbox name its embedders", () => { // A coordinator page frames sandboxes on other origins; frame-src would otherwise fall back to default-src 'self'. expect(contentSecurityPolicy({ frames: ["https://*.sandbox.example", "http://127.0.0.1:8972"] })).toMatch( /; frame-src 'self' https:\/\/\*\.sandbox\.example http:\/\/127\.0\.0\.1:8972$/, ); // frame-ancestors has no default-src fallback, so a sandbox only restricts its embedders when asked. expect(contentSecurityPolicy({ embedders: ["https://nibling.run"] })).toMatch(/; frame-ancestors https:\/\/nibling\.run$/); expect(contentSecurityPolicy()).not.toMatch(/frame-src|frame-ancestors/); expect(contentSecurityPolicy({ frames: [], embedders: [] })).toMatch(/; frame-src 'self'; frame-ancestors 'none'$/);
// A source that could end the directive is refused rather than written into the policy. for (const bad of ["https://a.example; script-src *", "https://a.example https://b.example", ""]) { expect(() => contentSecurityPolicy({ frames: [bad] })).toThrow(TypeError); expect(() => contentSecurityPolicy({ embedders: [bad] })).toThrow(TypeError); } expect(() => contentSecurityPolicy({ registry: "https://npm.example.test; script-src *" })).toThrow(TypeError);});
test("headersFor() serves a sandbox origin that a cross-site coordinator can embed", () => { expect(headersFor("/sandbox.html", { resourcePolicy: "cross-origin", csp: contentSecurityPolicy({ embedders: ["https://nibling.run"] }), })).toEqual({ "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "require-corp", "Cross-Origin-Resource-Policy": "cross-origin", "Content-Security-Policy": "default-src 'self'; script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval'; style-src 'self'; worker-src 'self'; connect-src 'self' data: blob:; frame-ancestors https://nibling.run", });});
test("connect-src always allows data: and blob: so a guest's fetch() of either never trips CSP", async ({ page }) => { // Neither scheme reaches the network, but Chrome still gates fetch() on connect-src // naming the scheme — demo/index.html is served with the real policy by scripts/serve.mjs. await page.goto("/demo/index.html"); const res = await page.evaluate(async () => { const data = await (await fetch("data:text/plain,hi")).text(); const blobUrl = URL.createObjectURL(new Blob(["hey"], { type: "text/plain" })); const blob = await (await fetch(blobUrl)).text(); return { data, blob }; }); expect(res).toEqual({ data: "hi", blob: "hey" });});
test("nibHeaders() sets headersFor()'s headers by decoded pathname and calls next", () => { const set: Record<string, string> = {}; const res = { setHeader: (name: string, value: string) => { set[name] = value; } }; const calls: unknown[][] = []; const mw = nibHeaders({ serviceWorkerAllowed: (p) => p === "/a b/sw.js" }); mw({ url: "/a%20b/sw.js?v=1" }, res, (...args) => { calls.push(args); }); expect(set).toEqual({ ...ISOLATED, "Service-Worker-Allowed": "/" }); expect(calls).toEqual([[]]);
// A pathname that does not decode is the server's error to report, not a crash. mw({ url: "/%E0%A4%A" }, res, (...args) => { calls.push(args); }); expect(calls[1]![0]).toBeInstanceOf(URIError);});