theseus/dev/origin-selftest.mjs
2026-09-12 00:07:42 +02:00

72 lines
3.6 KiB
JavaScript

// origin-selftest.mjs — verify the pure origin helper covers every case that
// window.bcnr permissions (B.3) and the password-autofill eTLD+1 upgrade
// (main.js:1257 stub) will lean on. No Electron needed.
//
// Usage: node dev/origin-selftest.mjs
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const { originOf, bnsEtldPlusOne } = require("../bcnr-origin.js");
const BCNR = ["bch", "wallet"]; // simulate the on-chain TLD list after warm-up
const cases = [
// ICANN — same permission origin for all subdomains of one registrable domain
["https://checkout.merchant.com/pay", "merchant.com"],
["https://blog.merchant.com/x", "merchant.com"],
["https://merchant.com/", "merchant.com"],
// Multi-part public suffixes — the reason we ship a real PSL, not a regex
["https://alice.co.uk/", "alice.co.uk"],
["https://pages.user.github.io/repo", "user.github.io"],
// Different registrable domain → different bucket, no cross-grant
["https://evil.com/", "evil.com"],
// BNS — root name is the identity; subdomains inherit it
["bns://silentmode.bch/", "silentmode.bch"],
["bns://pay.silentmode.bch/", "silentmode.bch"],
["bns://mail.silentmode.bch/x/y", "silentmode.bch"],
["bns://foo.wallet/", "foo.wallet"],
["bns://bar.foo.wallet/", "foo.wallet"],
// BNS with an unknown-to-us TLD — safest is to key the full host so a
// future TLD unlock doesn't silently expand old permissions.
["bns://foo.privateTld/", "foo.privatetld"],
// Dev origins — scheme+host+port matters, permissions don't cross ports
["http://localhost:3000/", "http://localhost:3000"],
["http://localhost:3001/", "http://localhost:3001"],
["http://127.0.0.1:8080/x", "http://127.0.0.1:8080"],
// Special / opaque
["about:blank", "about:blank"],
["file:///C:/Users/me/foo.html", "file://"],
["data:text/html,<h1>hi</h1>", null],
["blob:https://example.com/uuid", null],
// Junk in → null out (no crash)
["", null],
["not a url", null],
[null, null],
[undefined, null],
];
let pass = 0, fail = 0;
for (const [input, expected] of cases) {
const got = originOf(input, { bcnrTlds: BCNR });
const ok = got === expected;
console.log(`${ok ? "PASS" : "FAIL"} originOf(${JSON.stringify(input)}) → ${JSON.stringify(got)}${ok ? "" : ` (expected ${JSON.stringify(expected)})`}`);
ok ? pass++ : fail++;
}
// Direct bnsEtldPlusOne coverage — the BNS-specific branch, since it's the
// one PSL cannot help with.
const bnsCases = [
["silentmode.bch", BCNR, "silentmode.bch"],
["pay.silentmode.bch", BCNR, "silentmode.bch"],
["a.b.c.silentmode.bch", BCNR, "silentmode.bch"],
["bch", BCNR, null], // bare TLD — no registrable label
["single", BCNR, null],
];
for (const [host, tlds, expected] of bnsCases) {
const got = bnsEtldPlusOne(host, tlds);
const ok = got === expected;
console.log(`${ok ? "PASS" : "FAIL"} bnsEtldPlusOne(${JSON.stringify(host)}) → ${JSON.stringify(got)}${ok ? "" : ` (expected ${JSON.stringify(expected)})`}`);
ok ? pass++ : fail++;
}
console.log(`\n${pass} pass, ${fail} fail`);
process.exit(fail ? 1 : 0);