// 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,

hi

", 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);