fix(security): client href scheme check, outbound fetch timeouts, origin-scoped CORS (closes task/resolver-security-hardening)
Source: task/resolver-security-hardening (plan/steward-linker-security) — defense-in-depth: client trusted resolver href, outbound fetches had no timeout, CORS was blanket-*. - F1: extension/content.js makeLink re-validates primary.url scheme via a new pure Extract.isSafeHttpUrl helper (in extract.js, unit-tested); a non-http(s) url (javascript:/data:/garbage) is dropped and the plain text is kept. - F2: each of the three resolver outbound fetches (Spotify token, Spotify search, ollama /api/chat) now carries signal: AbortSignal.timeout(5000) so a hung upstream fails fast (caught per-candidate -> null), zero-dep. - F3: resolver CORS reflects the request Origin only for moz-extension://* or null (the extension's background-script origin), with Vary: Origin, instead of blanket access-control-allow-origin: *. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// CJS so it can require() extract.js, which is a UMD script (also a content script).
|
||||
const { test } = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { matchesIn, cueMatchesIn, albumMatchesIn, allMatchesIn } = require("./extract.js");
|
||||
const { matchesIn, cueMatchesIn, albumMatchesIn, allMatchesIn, isSafeHttpUrl } = require("./extract.js");
|
||||
|
||||
test("matchesIn finds Title-Case / ALL-CAPS runs, skips stopwords", () => {
|
||||
// Note: "and" is a connector, so "X and Y" greedily joins into one run (by design,
|
||||
@@ -64,6 +64,21 @@ test("albumMatchesIn skips pure-number and too-short quotes", () => {
|
||||
assert.ok(!names.includes("X")); // length < 2
|
||||
});
|
||||
|
||||
test("isSafeHttpUrl accepts http/https and rejects javascript/data/garbage/empty", () => {
|
||||
// accepted: the only schemes a resolver link may inject as an href
|
||||
assert.ok(isSafeHttpUrl("https://open.spotify.com/artist/abc"));
|
||||
assert.ok(isSafeHttpUrl("http://localhost:8787/x"));
|
||||
assert.ok(isSafeHttpUrl("https://www.google.com/search?q=Scum+bandcamp"));
|
||||
// rejected: dangerous schemes + non-URLs
|
||||
assert.ok(!isSafeHttpUrl("javascript:alert(1)"));
|
||||
assert.ok(!isSafeHttpUrl("data:text/html,<script>alert(1)</script>"));
|
||||
assert.ok(!isSafeHttpUrl("ftp://example.com/x"));
|
||||
assert.ok(!isSafeHttpUrl("not a url"));
|
||||
assert.ok(!isSafeHttpUrl(""));
|
||||
assert.ok(!isSafeHttpUrl(null));
|
||||
assert.ok(!isSafeHttpUrl(undefined));
|
||||
});
|
||||
|
||||
test("allMatchesIn merges cue + Title-Case + album and sorts ascending by index", () => {
|
||||
const text = `Check out devourment and Cattle Decapitation; the album "Human Jerky" rules`;
|
||||
const ms = allMatchesIn(text);
|
||||
|
||||
Reference in New Issue
Block a user