Merges a parallel session's work with the multi-source BNS story from 0.0.7.
The dApp side (parallel session)
--------------------------------
* bcnr-preload.js — installs `window.bcnr` on every page via contextBridge.
Read-only surface: resolveName(name), isRegistered(name), getBcnrTlds(),
getRecordVersion(name), plus getPermissionOrigin() for diagnostics. All
Promises; a missing name returns null (not throw). No signing, no wallet
unlock — that surface is designed but deliberately out of scope for 0.0.8
(see TheseusNavigator/DESIGN-integrated-wallet.md).
* bcnr-origin.js — pure function that computes the eTLD+1 permission origin
for a URL. ICANN suffixes via `psl` (same PSL Chromium uses, handles
.co.uk / .github.io / etc); BNS names key off the on-chain TLD list so
foo.wallet becomes a public suffix as soon as `wallet` appears there.
Match browser cookie / MetaMask semantics: a grant on pay.merchant.com
covers account.merchant.com but not evil.com.
* dev/bcnr-selftest.js, dev/origin-selftest.mjs — self-tests, no I/O.
* main.js wires bcnr-preload.js into session.defaultSession.setPreloads() so
it runs BEFORE per-WebContentsView preloads; adds bcnr:* IPC handlers.
* preload.js + chrome.html — small hooks so the shell picks up window.bcnr
the same way regular content does.
* package.json — psl dep, bcnr-preload.js/bcnr-origin.js in `files`.
Also included
-------------
* AriadneResolver/mobile/.../UpdateCheck.java — in-app update-check for the
Android app; already active in the shipped 0.11 APK (build.ps1 -Recurse
picked it up), formalising the source now.
* TheseusNavigator/snapshots/bns-name-snapshot.json — refreshed bundled
starter (73 beacon txs, root c37b8596…c54e414ba).
* Site pages + manifest updated to point at 0.0.8.
TheseusNavigator-Setup-0.0.8.exe 95.4 MB
21939743eafdfe8742a6b7c4b987bd2782384d7bc41289cb80a7e08019dc9f02
TheseusNavigator-0.0.8-portable.exe 92.7 MB
2aa429fe39dc0fa4ac040fc6d6eb31b0f890c8a83175c49fcb50f052c480d39d
72 lines
3.6 KiB
JavaScript
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);
|