feat(gateway): accept *.bns.navigate.st alongside *.bch.navigate.st

Preparing to rename the subdomain namespace from .bch to .bns. ".bch"
reads as "Bitcoin Cash TLD" but is applied uniformly to names on every
BCDN TLD — sirius-x.bch.navigate.st reads wrong when sirius.x is a .x
name. ".bns" (Bitcoin Cash Name Service — the real protocol name) is
the same length, carries meaning, and doesn't lie about the name's TLD.

Transition approach (no cutover required):
  * BNS_SUB_BASE keeps defaulting to "bch.navigate.st" — primary suffix
    for new URLs (banner "Isolated view", OG hints) stays unchanged
    until the .bns wildcard cert is issued.
  * BNS_SUB_BASE_LEGACY, defaulting to "bch.navigate.st,bns.navigate.
    st", lists every suffix the inbound matcher accepts. Both forms
    resolve to the same name via the existing subdomainLabelToName.
  * Bare apex of ANY accepted suffix serves the gateway home.

Verified: sirius-x.bch.navigate.st still 200s, and curl -H
'Host: sirius-x.bns.navigate.st' http://127.0.0.1:8700/ returns the
same Sirius.X HTML (gateway handler accepts both; the public TLS
termination for .bns.navigate.st is pending the wildcard cert).

Rollout:
  1. Issue *.bns.navigate.st wildcard (DNS-01, manual TXT on nymdns)
  2. ln -s /etc/nginx/sites-available/bns-subdomain (staged)
  3. systemctl reload nginx
  4. Flip BNS_SUB_BASE=bns.navigate.st so new banner links use .bns.
  5. Keep .bch. live for ~6 months as the deprecation window closes.
This commit is contained in:
Local Dev 2026-10-07 19:12:48 +02:00
parent eb20a5b778
commit 8979ec11cc

View file

@ -257,7 +257,22 @@ async function activeListings() {
return keep;
}
const S3_ENDPOINT = process.env.BNS_S3 || "http://127.0.0.1:8500";
const SUB_BASE = (process.env.BNS_SUB_BASE || "bch.navigate.st").toLowerCase(); // subdomain suffix
// Primary subdomain suffix — new URLs (banner "Isolated view" link, OG
// hints, etc.) are built against this. Flip to "bns.navigate.st" once the
// wildcard cert is issued; "bch.navigate.st" remains the current default
// so no cutover is required.
const SUB_BASE = (process.env.BNS_SUB_BASE || "bch.navigate.st").toLowerCase();
// Every suffix the inbound-matching accepts. "bch.navigate.st" was the
// original and stays live for the ~6-month deprecation window; "bns.
// navigate.st" is the renamed form (BNS = Bitcoin Cash Name Service, the
// actual protocol name, instead of the misleading .bch segment on
// non-.bch names like sirius-x.bch.navigate.st). Both decode through the
// same subdomainLabelToName.
const SUB_BASE_ALL = Array.from(new Set([
SUB_BASE,
...(process.env.BNS_SUB_BASE_LEGACY || "bch.navigate.st,bns.navigate.st")
.toLowerCase().split(",").map((s) => s.trim()).filter(Boolean),
]));
// ---------- VPN exit catalogue + session leases ----------
// The pool file holds, per exit, the Reality parameters a client needs AND a
@ -2500,8 +2515,9 @@ const server = http.createServer(async (req, res) => {
// Legacy form (back-compat): a dot-less single label implicitly meant
// "<label>.bch" — `hello.bch.navigate.st` used to resolve "hello.bch".
// We preserve that so existing bookmarks keep working.
if (hostHeader.endsWith("." + SUB_BASE)) {
const inner = hostHeader.slice(0, -("." + SUB_BASE).length);
const matchedBase = SUB_BASE_ALL.find((b) => hostHeader.endsWith("." + b));
if (matchedBase) {
const inner = hostHeader.slice(0, -("." + matchedBase).length);
if (inner) {
let name = subdomainLabelToName(inner).toLowerCase();
if (!name.includes(".") && /^[a-z0-9-]+$/i.test(name)) {
@ -2515,8 +2531,8 @@ const server = http.createServer(async (req, res) => {
}
}
}
// bare apex of SUB_BASE (e.g. bch.navigate.st) -> home
if (hostHeader === SUB_BASE) { res.writeHead(200, { "content-type": "text/html" }); return res.end(home()); }
// bare apex of any accepted SUB_BASE -> home
if (SUB_BASE_ALL.includes(hostHeader)) { res.writeHead(200, { "content-type": "text/html" }); return res.end(home()); }
// --- path form: /bns/<name>.bch/... ---
let p = req.url;