Merge ship/mirrors-and-cf: branded error pages and the mirrors docs

These three commits were pushed to the forge's theseus and site repos
from their branch but never reached master, so pushing master would
have dropped them there. Merged so master carries them: the branded
error page on BCNR-to-clearnet fallback failures, the Cloudflare Bot
Fight 503 hint with a .bch mirror suggestion, and the site's docs page
for the p-record reverse-proxy workaround.
This commit is contained in:
Local Dev 2026-10-04 15:14:59 +02:00
commit c8ab0e239b
2 changed files with 201 additions and 0 deletions

194
mirrors/index.html Normal file
View file

@ -0,0 +1,194 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mirrors — Silent Mode</title>
<meta name="description" content="Cloudflare's Bot Fight Mode fingerprints Electron's TLS handshake and blocks Theseus with HTTP 503. BNS `p` records reverse-proxy the request through Node's HTTP stack, bypassing the fingerprint — Theseus renders the page under a .bch name.">
<link rel="stylesheet" href="../shared.css">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<style>
.mirror-list{display:grid;gap:10px;margin:1rem 0 1.4rem}
.mirror{
display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;
background:var(--panel);border:1px solid var(--line);border-radius:12px;
padding:14px 18px;
}
.mirror .row1{font:600 15px/1.35 ui-monospace,monospace;color:var(--acid)}
.mirror .row2{color:var(--mut);font-size:12.5px;margin-top:3px;
font-family:ui-monospace,monospace;word-break:break-all}
.mirror .badge{
font:600 10.5px/1 system-ui;letter-spacing:.18em;text-transform:uppercase;
color:var(--acid);background:rgba(214,255,61,.10);
border:1px solid rgba(214,255,61,.28);padding:5px 9px;border-radius:999px;
white-space:nowrap;
}
.empty-note{
color:var(--mut);font-size:13px;padding:14px 16px;
background:var(--panel2);border:1px dashed var(--line);border-radius:10px;
}
code.k{font-family:ui-monospace,monospace;background:var(--panel2);
padding:1px 6px;border-radius:5px;color:var(--acid)}
.step{display:flex;gap:14px;padding:12px 0}
.step + .step{border-top:1px solid var(--line)}
.step .n{flex:none;width:26px;height:26px;border-radius:999px;
background:rgba(214,255,61,.10);color:var(--acid);
display:grid;place-items:center;font:600 12px/1 system-ui}
.step .b{color:var(--mut);font-size:14px;line-height:1.6}
.step .b b{color:var(--ink)}
</style>
</head>
<body>
<nav class="topnav">
<a class="brand" href="./"><svg class="logo" viewBox="0 0 32 20" aria-hidden="true"><rect class="l1" x="1.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/><rect class="l2" x="13.5" y="3.5" width="17" height="13" rx="6.5" ry="6.5" fill="none" stroke-width="2.6"/></svg>Silent <span class="g">Mode</span></a>
<a href="theseus">Theseus</a>
<a href="prometheus">Prometheus</a>
<a href="sirius">Sirius</a>
<a href="hephaestus">Hephaestus</a>
<a href="helios">Helios</a>
<a href="hermes">Hermes</a>
<a href="tools">Tools</a>
</nav>
<header class="hero">
<h1>Reverse-proxy <span class="g">mirrors</span></h1>
<p class="tag">Some sites — including several of the most-cited pages in the Bitcoin
Cash ecosystem — return <b>HTTP 503</b> to Theseus, no matter what user-agent it sends.
A short note on why, and how a <code class="inline">.bch</code> name gets you through.</p>
</header>
<div class="wrap">
<!-- ============ WHAT'S HAPPENING ============ -->
<section>
<h2>Why Theseus 503s on some sites</h2>
<p class="lede">Cloudflare's Bot Fight Mode (and similar WAF rules) fingerprints the
<b>TLS ClientHello</b> — the cipher list, extensions, and JA3/JA4 hash your browser
sends before any HTTP header is negotiated. Chromium's TLS stack, which Theseus is
built on via Electron, ships with a slightly different fingerprint than desktop
Chrome — enough to trigger the bot heuristic. The server replies with a short
503 page and the load fails.</p>
<p class="lede">Stripping <code class="inline">Electron/…</code> from the user-agent
doesn't help: the fingerprint sits below HTTP. Disabling HTTP/2 doesn't help either.
From the site's perspective, Theseus is indistinguishable from a scraper.</p>
</section>
<!-- ============ THE FIX ============ -->
<section>
<h2>What a <code class="inline">p</code> record does</h2>
<p class="lede">A BCDN name can carry a <code class="inline">p</code> record — a
single upstream URL. When Theseus loads a name whose record picker returns
<code class="inline">p</code>, it doesn't hand the request to Chromium's network
stack. It hands it to <b>Node's <code class="inline">fetch()</code></b> from the
main process, which uses a different HTTP client (undici) with a completely
different TLS fingerprint — one Cloudflare doesn't flag. The response body comes
back and gets served under the <code class="inline">.bch</code> origin.</p>
<p class="lede">The address bar stays on the BNS name; the upstream never sees your
IP resolve through Cloudflare's browser-bot rules, only through Theseus's outbound
Node fetch. No captcha, no interstitial, no 503.</p>
<p class="lede">Trade-offs to know: the <code class="inline">p</code> path uses the
upstream's own DNS and public certificate authority (unlike <code class="inline">ip</code>,
which pins to a raw IP + on-chain TLS fingerprint), and Theseus streams the body
through its own process — so the upstream sees Theseus's outbound IP, not yours.
This is a shared proxy in effect, though only for the one request.</p>
</section>
<!-- ============ FEATURED MIRRORS ============ -->
<section>
<h2>Featured mirrors</h2>
<p class="lede">These names are registered on the Bitcoin Cash chain with a
<code class="inline">p</code> record pointing at a Cloudflare-fronted upstream
Theseus can't reach directly. Click any to open it in Theseus (or via
<a href="https://navigate.st/">navigate.st</a> if you don't have the browser
installed yet).</p>
<div class="mirror-list" id="mirror-list">
<!-- Populated at ship time. Keep entries in sync with site/home-cards.json's
"Mirrored" section so the home tiles and this page tell the same story. -->
<div class="empty-note">
<b>No mirrors published yet.</b> The list will fill in as names are minted
through Sirius. Check back, or mint one yourself — instructions below.
</div>
</div>
<p class="lede" style="margin-top:1.2rem">
<b>See a site missing?</b> If a Cloudflare-fronted page you care about is
unreachable from Theseus, either mint a <code class="inline">p</code> record for
it yourself, or open an issue on
<a href="https://code.silentmode.st/silentmode/theseus">the Theseus repo</a> and
we'll add it to the featured list once it's on chain.
</p>
</section>
<!-- ============ DIY ============ -->
<section>
<h2>Mint a mirror yourself</h2>
<p class="lede">Registration costs a few sats of BCH. Theseus 0.3.14+ ships with the
<b>Aegis wallet</b> — the wallet the Sirius UI signs against — so this is a couple
of clicks once your wallet has a small balance.</p>
<div>
<div class="step">
<div class="n">1</div>
<div class="b">Open <a href="https://sirius.x/">sirius.x</a> in Theseus and search
for the label you want. Pick a <code class="k">.bch</code> TLD if the site is
BCH-related; other registered TLDs work too. Mint the name.</div>
</div>
<div class="step">
<div class="n">2</div>
<div class="b">Once minted, open the name's record editor and add:
<br><code class="k">p: "https://the-original-upstream.example/"</code>
<br>The trailing slash matters — anything in the path is used as a prefix
for every request.</div>
</div>
<div class="step">
<div class="n">3</div>
<div class="b">Sign the record change. Wait one confirmation. The record is live
as soon as the next Theseus resolve fetches the beacon.</div>
</div>
<div class="step">
<div class="n">4</div>
<div class="b">Test: type <code class="k">yourname.bch</code> in Theseus's address
bar. If the upstream returns 200, Theseus renders it under your name. Send us
the name and we'll add it to the featured list.</div>
</div>
</div>
<div class="note" style="margin-top:1.4rem">
<b>Be honest about what a mirror is.</b> The upstream is unchanged — the site
operator hasn't consented to being served under your BNS name, and doesn't get
paid for any traffic that lands through the mirror. This is a workaround for a
reachability problem, not a rehosting. If you'd rather leave the mirror to us,
open an issue and we'll consider whether it's canonical enough to include.
</div>
</section>
<!-- ============ TECHNICAL DETAIL ============ -->
<section>
<h2>The relevant code</h2>
<p class="lede">For anyone curious about the exact mechanism:</p>
<ul style="color:var(--mut);font-size:14px;line-height:1.7;padding-left:1.2rem">
<li>Record priority — <code class="inline">pickRecord()</code> in Argus:
<code class="inline">h &gt; s3 &gt; ip &gt; p &gt; u</code> at the apex, and
subdomain inheritance never picks <code class="inline">p</code>. Theseus
carries an inline copy to keep in step.</li>
<li>Theseus proxy pipeline — <a href="https://code.silentmode.st/silentmode/theseus/src/branch/master/main.js"><code class="inline">theseus/main.js</code></a>,
the <code class="inline">serveP</code> closure inside <code class="inline">serveBns()</code>.
Uses <code class="inline">fetch(target, { redirect: "manual" })</code>
from the main process, which is Node's undici — a different TLS stack from
Chromium's, and the reason the fingerprint check doesn't fire.</li>
</ul>
</section>
</div>
<footer>
<div>Silent Mode — a Deviant project.</div>
<div class="fine">Mirrors are provided as-is. The upstream site's terms and privacy
policy still apply — a <code class="inline">.bch</code> name changes only how the
bytes reach you, not who wrote them.</div>
</footer>
</body>
</html>

View file

@ -189,6 +189,13 @@
</div>
</div>
<div class="note" style="border-left-color:var(--acid)"><b>Some sites 503 in Theseus.</b>
Cloudflare's Bot Fight Mode fingerprints Electron's TLS handshake and blocks it, no
matter what user-agent Theseus sends. The workaround is a BCDN
<code class="inline">p</code> record that reverse-proxies the site through Node's
HTTP stack — see <a href="../mirrors">Reverse-proxy mirrors</a> for the featured
list and how to mint your own.</div>
<div class="note"><b>Not in a store.</b> Neither version is on the Microsoft Store,
Google Play or the App Store. Distributing there requires a legal identity and the
store's permission, the two things this project exists to do without. You will have