Commit graph

8 commits

Author SHA1 Message Date
Silent Mode
9c8b2bfafe feat(gateway): a name's owner decides what its subdomains serve
Until now a subdomain served the folder its labels spelled out, and that was
the only thing it could ever do. There was no way to point one somewhere
else, send one to another site, or stop one answering — the mapping was a
convention with no override.

A verified hosts entry now decides: a different folder, a redirect, or
nothing at all. Block beats redirect beats path, so a host that is both
blocked and redirected stays blocked. The manifest is fetched only when the
request is actually for a subdomain, and the result — including the absence
of one — is cached for a minute, so the apex pays nothing and a name that
never published one pays one lookup per minute rather than one per request.
A manifest that fails to verify is treated exactly like no manifest: the
name keeps serving from its chain records instead of failing shut.

The folder derivation moves next to the picking rule and grows tests,
because getting it wrong does not raise an error — it quietly serves the
wrong bytes. The subtle parts are that labels reverse (DNS reads outward, a
path reads inward) and that a .bch name indexes as <label>.bch even though
normalizeName collapses it to a bare label; matching the bare label would
have served the bucket root for every subdomain of every .bch name.

/api/dns answers for a host too. A host with its own dns block owns its
record set outright, the way classic DNS works; one without inherits the
apex, the way everything else on BNS does.
2026-09-28 01:04:36 +02:00
Silent Mode
98232def96 refactor(gateway): one definition of what makes a signed manifest valid
The signature check was written out twice — once on the read path, once on
the write path — and a third copy was about to be needed for serving. Three
hand-copies of a verification routine is how a hole gets in, and the
dangerous half is subtle: pubkey recovery always succeeds and always yields
some key, so the line that actually proves anything is the comparison of the
derived address to the on-chain owner. That line is now in one place.

The manifest schema gains a hosts block for per-subdomain records and
routing, validated strictly here because whatever we accept we then serve
under the owner's signature: no path traversal, no non-http redirect
targets, no host key that is not a label path. v1 blobs stay valid, so
nothing anyone has published needs republishing.

Also adds the rule for which hosts entry governs a request. The apex is
deliberately never one of them — its content comes from the chain, and
letting an off-chain blob redirect the main site would move a name's trust
boundary without the owner spending a transaction.
2026-09-28 01:01:27 +02:00
Local Dev
408f965629 feat(bns): 'p' reverse-proxy record type — mirror an upstream URL under a BNS name
New record kind alongside h / s3 / ip / u: `p` reverse-proxies the
request to a full upstream URL while keeping the BNS host in the
address bar. Unlike `ip` (which pins the upstream to a raw IP + on-chain
TLS fingerprint), `p` uses the upstream's own DNS + public CA cert and
sends `Host:` of the upstream so vhost-based origins answer correctly.

Argus (record-picker.js):
- Placed AFTER `ip` in the apex chain: a name carrying both keeps its
  existing pinned-IP behavior; names with only `p` get honored instead
  of falling through to `u` and 302-ing away.
- Not applied to subdomain inheritance — `p` is single-URL by intent,
  and inheriting through a subdomain would silently mangle the target.

Theseus (main.js serveBns):
- Fetches the upstream (path prefix from the `p` URL is preserved) and
  returns the response body/status/content-type verbatim. Provenance
  label "mirror" appears in the source badge.

Tests: record-picker.test.mjs covers `p`-only, `p`+ip precedence, and
the subdomain-suppression rule.
2026-09-07 00:18:07 +02:00
Local Dev
9068eff9c7 BNS: per-TLD on-chain registry, multi-beacon indexer, enforcement gate
Per-TLD certificates on a distinct TLD beacon supersede the legacy list-in-one-NFT
model. TLD label is the NFT commitment; TREG/TUPD payloads on the TLD beacon
mirror REG/UPD on the name beacon. Chipnet TLD beacon:
  bchtest:qzc4c76vtw9nd49g6x8nmvc0jz62uvk4dc7hmpmerh
  scripthash c85db10e106606273422b2733b2a6fb8b35a4d0e7dbfb20cf59bdb0833c008b8

  * config.js, resolver-web.{js,d.ts} — TLD_BEACON + TLD_BEACON_SCRIPTHASH
  * bns.js — KNOWN_OPS { REG, UPD, TREG, TUPD }, registerTld/updateTld/normalizeTld
  * bns.js + resolver-web.js — buildIndex({enforceTld:false}) drops name REGs
    whose TLD lacks a live TLD cert at their block height (mempool-friendly).
    Lockstep across both files.
  * lib/tld-index.js — buildTldSnapshot({history,txs}) → deterministic root over
    canonicalised tlds[]. Pure, importable, and stable across insertion order.
  * indexer/bns-indexer.js — BeaconIndex is multi-beacon; ws handler dispatches
    by scripthash; new HTTP endpoint GET /tld-list.json + /health behind
    BNS_HTTP_PORT; state file v1 → v2 migrates in fromJSON.
  * publish-tld-mirror.mjs — S3 (floating + immutable content-addressed) plus
    NIP-33 kind 30078 d:bns-tld-list to Nostr relays, signed via nostr-tools
    (libauth's Schnorr differs from BIP-340 and relays reject it).
  * seed-tld-beacon.mjs — idempotent chipnet seed. Current set on the beacon:
    bch p2p bit nav test x asm neo gt sc sia com dex cex nt (15). `.com` is
    held by the operator: cert on-chain, excluded from public registrar UI.

Design + docs:
  * Decentralized.DNS/DESIGN-tld-registry.md — schema, enforcement,
    operator-countersig gate, USD-tiered pricing floors, fee splits,
    tracker/mirror mechanics, migration/grandfathering.
  * INSTRUCTIONS.md §3 rewritten for the 4-step flow (TREG → UI → deploy →
    republish snapshot).
  * site/tlds/ — public docs page listing current TLDs + verification paths.
  * site/sirius/register.html — dropdown removed; parallel search across
    every TLD in the TLDS array, sorted available → taken → not-on-registry.

Config:
  * ariadne.config.json tlds → [bch, p2p, bit, nav, test, x]  (CA constraints;
    on-chain registry is now the authoritative source, config is fallback).
  * setup/install.ps1 — reads TLD list via fetchTldList (per-TLD registry)
    with fallback to fetchBcnrTlds (legacy tls.bch list-NFT) then config.

Tests:
  * test/tld-index.test.mjs — 30 self-contained checks (multi-beacon dispatch,
    state migration, ws routing, snapshot shape + root recomputability).
  * test/tld-enforcement.test.mjs — synthetic + live chipnet integration
    (with-gate correctly drops all pre-seed names).
2026-08-29 17:11:02 +02:00
Local Dev
b4a550ef41 Snapshot in-progress work: Ariadne mobile, Theseus password manager, Hephaestus
Several concurrent workstreams committed together as a checkpoint:

- Ariadne mobile resolver — BchFetcher/Bns/MainActivity resolution logic,
  AndroidManifest + build.ps1
- Theseus password manager — settings.html/chrome.html/settings-preload.js UI +
  main.js wiring + package.json resource; Argus password-vault.js, record-picker.js
  (+ tests) and resolver-web.d.ts
- Hephaestus — new BCH-wallet OIDC auth-proxy + Forgejo docker-compose and
  restic/S3 scripts (secrets referenced via env only; Hephaestus/.env is gitignored)
- Argus public-gateway.mjs updates
- Docs — root README, Email README/RUNBOOK, VPS access runbooks (Checkers/Deviant),
  site/hermes, WebsiteDev registry + faster-blocks, Failures/ AAAA-mangle writeup,
  Decentralized Storage map, coordination notes
- .gitignore — exclude /.keys/ and Hephaestus/.env
2026-08-14 23:17:18 +02:00
Local Dev
83a8fff021 resolver: echo EDNS OPT record so strict clients stop failing
Root cause of the "Firefox 'Server Not Found' (github)" and Node
`getaddrinfo EAI_FAIL` reports against the shipped daemon: reply() in
bnsd.js built responses from scratch and never copied the query's EDNS0
OPT record from the additional section. RFC 6891 §6.1.1 requires the
response to echo OPT when the query carried one; strict clients (glibc
getaddrinfo, Firefox with TRR off) treat the missing OPT as FORMERR and
surface EAI_FAIL / "Server Not Found". Lenient clients (nslookup, Chrome
async-dns) tolerate the loss, which is why the bug looked flaky.

The prior commit (ef19db1) extracted src/lib/dns-server.js as a testable
surface but left bnsd.js still calling the old inline helpers. This
finishes the migration:

- src/lib/dns-server.js:
  - buildReply() now walks the additional section, finds the OPT RR by
    name=root/type=41, and appends it to the response. When the query
    had no OPT, none is fabricated (RFC 6891 §7). Preserves RD and
    opcode from the query rather than hardcoding 0x8580.
  - parseQuestion() rejects QDCOUNT != 1 and truncated labels early,
    and skipName() tolerates DNS compression pointers per RFC 1035
    §4.1.4 so the OPT walker doesn't trip on a compressed name.
  - forwardQuery() accepts "host" (default port 53) or "host:port" so
    it can be tested off port 53.

- src/daemon/bnsd.js: replaces the inline helpers with imports; the
  icann-first branch keeps its rcode-inspecting callback via a small
  forwardInspect() wrapper around the Promise-based forwardQuery.

- test/dns-server.test.mjs (new): 14 tests. Includes parseQuestion
  cases (plain / EDNS / bad QDCOUNT / truncated), buildReply invariants
  (OPT echoed / OPT never fabricated / RD preserved / NODATA still
  echoes OPT), full dns.Resolver round-trips against an in-process
  server (A / AAAA-NODATA / forward-to-mock-upstream), and two pinned
  regression tests that copy the OLD reply() verbatim and assert its
  OPT-dropping behavior so a future regression is caught immediately.

- AriadneResolver/ariadne-resolver/{src/daemon/bnsd.js, src/lib/dns-server.js}:
  synced from Argus so the packaged installer picks up the fix.

Pre-existing failures in test/portfolio-index.test.mjs (require is not
defined at src/lib/chain.js:54) are unrelated and predate this work.
2026-08-02 01:19:09 +02:00
Local Dev
f9a5eb367f Theseus navigator UI overhaul, BNS-only indexer, site restructure
Theseus Navigator:
- Firefox-style toolbar: SVG back/fwd/reload/home buttons
- security padlock badge in the address bar opens a floating site-info
  overlay VIEW (on top of the page, never pushes content down)
- Edge-style favorites bar (shown only on the new-tab/home page)
- search-engine picker (DuckDuckGo/Google/Bing/Brave/Startpage)
- Theseus logo moved right, opens Settings; native menu removed
- address bar doubles as search; bottom resolver status line

Argus:
- BNS-only indexer: an electrum endpoint over a bare BCHN node
  (watches just the beacon, caches txs so no txindex needed) + test
- registry lifecycle / portfolio / name-index modules

Site restructure (nav/apps/store/hermes/choose) + runbook notes.
2026-07-30 08:16:55 +02:00
Local Dev
a45320db7d Initial commit — Silent Mode baseline (2026-07-29)
Snapshot of the decentralized-web stack at the point of the resolver+Theseus
rebuild deploy. Includes:

- Argus (BNS engine + resolver daemon + Sia gateway)
- AriadneResolver (Windows Inno installer bundle + Android APK sources +
  Firefox extension)
- TheseusNavigator (Electron browser)
- site/ (silentmode.st content, deployed to Sia at bns/silentmode/)
- design docs, roadmap, protocol spec

Secrets excluded via .gitignore: Argus/sia-s3.json, Argus/wallets.json,
Argus/ca/*.key,*.crt. Build outputs, node_modules, and bundled runtimes
also excluded.

Shipped hashes on dl.silentmode.st at this commit:
  AriadneResolver-Setup-0.1.0.exe    5bcb216eef31ea28ed767e4134ab74bd5ac69dfbd365fd249e9e6938e55c986a
  TheseusNavigator-Setup-0.0.1.exe   7c735e88bad2da3347145adba3016c8f626a18b8422289c8c6ba471972e2952b
  TheseusNavigator-0.0.1-portable.exe 008fd84445babeabb401b2bca40ea9466b24b0e6d6c85104da7640c5c5c84521
  ariadne-v0.2.apk                   635c8f04d44ef855a8390b9eeddb8cd2d50622e81cc4e5004e8daffc1bb0425c
2026-07-29 13:54:34 +02:00