Skip to content

Commit c8a18d6

Browse files
committed
fix: apply custom html csp over static defaults
1 parent d805168 commit c8a18d6

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

scripts/workers/worker.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ async function withSecurityHeaders(response, context) {
7171
if (!headers.has(name)) headers.set(name, value);
7272
}
7373

74-
if (!response.headers.has("content-security-policy") && (await isCustomHtmlAsset(assetPath, response, context))) {
74+
if (await isCustomHtmlAsset(assetPath, response, context)) {
7575
headers.set("content-security-policy", CUSTOM_HTML_CONTENT_SECURITY_POLICY);
7676
}
7777

@@ -971,7 +971,7 @@ function preferredContentLanguages(request) {
971971
quality: quality ? Number.parseFloat(quality.slice(2)) : 1
972972
};
973973
})
974-
.filter((entry) => LOCALIZED_HTML_LANGUAGES.includes(entry.language) && entry.quality > 0)
974+
.filter((entry) => ["en", ...LOCALIZED_HTML_LANGUAGES].includes(entry.language) && entry.quality > 0)
975975
.sort((a, b) => b.quality - a.quality)
976976
.map((entry) => entry.language);
977977
}

scripts/workers/worker.test.mjs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,17 @@ const assets = {
137137
}
138138
}),
139139
"/custom-page.html": html("<main>custom page</main>"),
140+
"/custom-default-csp.html": new Response("<main>custom default csp</main>", {
141+
headers: {
142+
"content-type": "text/html; charset=utf-8",
143+
"content-security-policy":
144+
"default-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; connect-src 'self' https://api.github.com; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
145+
}
146+
}),
140147
"/v8s.json": Response.json(registry),
141148
"/v8s-custom-assets.json": Response.json({
142149
schema_version: 1,
143-
paths: ["/custom-page.html", "/v8s-style.css"]
150+
paths: ["/custom-page.html", "/custom-default-csp.html", "/v8s-style.css"]
144151
}),
145152
"/v8s-blocklist.json": Response.json({
146153
blocked_keywords: [
@@ -443,6 +450,21 @@ await run("serves homepage from static assets", async () => {
443450
assert(!("data" in analyticsCalls[0].body.payload), "regular pageview has no event data");
444451
});
445452

453+
await run("serves English when Accept-Language prefers English over another supported language", async () => {
454+
const ctx = mockCtx();
455+
const response = await worker.fetch(
456+
request("/", {
457+
headers: { "accept-language": "en-CA,en;q=0.9,fr;q=0.8" }
458+
}),
459+
env(),
460+
ctx
461+
);
462+
assert(response.status === 200, "status");
463+
assert((await response.text()).includes("home en"), "English localized home body");
464+
assert(response.headers.get("content-language") === "en", "content language");
465+
await ctx.flush();
466+
});
467+
446468
await run("serves localized policy and lookup pages from Accept-Language", async () => {
447469
for (const [path, expected] of [
448470
["/privacy", "confidentialite fr"],
@@ -570,6 +592,12 @@ await run("applies sandboxed CSP only to custom HTML assets", async () => {
570592
assert(csp.includes("'unsafe-inline'"), "custom html allows inline assets");
571593
assert(!custom.headers.has("x-v8s-asset-path"), "internal asset path stripped");
572594

595+
const customDefault = await worker.fetch(request("/custom-default-csp.html"), env(), mockCtx());
596+
assert(
597+
customDefault.headers.get("content-security-policy").includes("sandbox allow-scripts"),
598+
"custom html overrides default static CSP"
599+
);
600+
573601
const css = await worker.fetch(request("/v8s-style.css"), env(), mockCtx());
574602
assert(!css.headers.get("content-security-policy").includes("sandbox"), "custom non-html keeps default csp");
575603
});

0 commit comments

Comments
 (0)