harden: drop 'unsafe-inline' from style-src (closes #328)
check / check (push) Failing after 3s
e2e / e2e-chrome (push) Failing after 2s
e2e / e2e-firefox (push) Failing after 2s

The popup's markup no longer carries style attributes. The 42 in
index.html and in the HTML the view helpers build are now Tailwind
classes, each computing to the value it replaced, so style-src is 'self'
in both manifests, pinned in tests/manifest.test.js.

The address dot's 16 colours are written out as whole classes, because
Tailwind builds only the classes it finds in the source. The Settings
debug well is shown and hidden with the hidden class, since clearing an
inline display no longer uncovers it. Two tests that found the colour dot
by its inline style now find it by its class. Script that sets
element.style is unaffected.

Model: opus-5-5
This commit is contained in:
2026-10-05 12:14:42 +00:00
parent 9bd607b411
commit 6c005b7893
13 changed files with 108 additions and 147 deletions
+2 -2
View File
@@ -301,7 +301,7 @@ describe.each([
test("a contract creation's row says so, with no colour dot and no address line", async () => {
const html = await rowsFor(historyTx(""));
expect(html).toContain(SENTENCE);
expect(html).not.toContain("background:");
expect(html).not.toContain("bg-[#");
expect(html).not.toContain("am-address");
expect(html).not.toContain("undefined");
});
@@ -309,7 +309,7 @@ describe.each([
test("a transaction with a recipient shows its colour dot and address", async () => {
const html = await rowsFor(historyTx(RECIPIENT));
expectAddressLine(html);
expect(html).toContain("background:#");
expect(html).toContain("bg-[#");
expect(html).toContain(`<div class="am-address">${RECIPIENT}</div>`);
});
});
+1 -1
View File
@@ -311,7 +311,7 @@ test("transaction detail renders an ERC-20 transfer (#151)", async (env) => {
"token contract row missing the contract address, got: " +
JSON.stringify(contractText),
);
const dots = await contract.locator('span[style*="border-radius"]').count();
const dots = await contract.locator('span[class*="rounded-[50%]"]').count();
assert(dots > 0, "token contract row rendered without its colour dot");
});
+7 -8
View File
@@ -21,15 +21,14 @@
// escaping in src/shared/html.js is the primary fix; default-src is what
// stops the next escape that slips from reaching the network.
//
// Every directive below is pinned exactly, because each of the four
// And for #328: style-src is 'self' alone, so the browser refuses every
// style="..." attribute in the popup's markup, including one an escape lets
// through. The popup styles with classes; script setting element.style is
// not affected.
//
// Every directive below is pinned exactly, because each of the three
// loosenings is load-bearing and none of them may grow:
//
// style-src 'unsafe-inline' src/popup/index.html and the view helpers
// use style="..." attributes throughout, which
// CSP blocks without it. Chrome enforces this
// on attributes, not just <style> blocks, and
// Firefox has never implemented style-src-attr,
// so there is no narrower spelling available.
// img-src data: blockies are data: PNGs assigned to img.src.
// connect-src https: http: the RPC endpoint is user-configurable, and a
// local node over http://127.0.0.1 is a
@@ -58,7 +57,7 @@ const EXPECTED_DIRECTIVES = {
"default-src": ["'self'"],
"script-src": ["'self'", "'wasm-unsafe-eval'"],
"object-src": ["'self'"],
"style-src": ["'self'", "'unsafe-inline'"],
"style-src": ["'self'"],
"img-src": ["'self'", "data:"],
"connect-src": ["'self'", "http:", "https:"],
"frame-src": ["'none'"],