feat(electrumx): add relay.testls.bit endpoints (clearnet TLS + Tor)

Adds the relay.testls.bit ElectrumX-NMC deployment as a second public
Namecoin name resolver. The same box also runs the Namecoin-anchored
Nostr relay at wss://relay.testls.bit/, so a single TLSA record on
d/testls anchors the trust chain for both services.

Default server set (clearnet):
  + relay.testls.bit:50002      (TLS, self-signed cert pinned)

Tor server set (onion-first):
  + 6cbn4rsk...onion:50001      (plaintext over Tor; re-uses the
                                 relay's existing v3 hidden service,
                                 onion key already authenticates)
  + relay.testls.bit:50002      (clearnet TLS fallback)

Cert pin (SHA-256 of DER):
  bb0b35e64235a794e157b69acd72da4ccc16a4d81d0ff6b1d8f7fdfc6cca6cba

The new self-signed cert is appended to PINNED_ELECTRUMX_CERTS so
strict-TLS Android devices (Samsung One UI 7, GrapheneOS) accept it
without a trust-all fallback.

Reference deployment also exposes wss://relay.testls.bit/electrumx
(WebSocket transport for browser-based Nostr clients), which inherits
the relay's existing TLSA-pinned ECDSA cert from d/testls. The current
JVM ElectrumXClient is TCP+TLS only; adding a WS variant of the client
is a larger change and tracked separately.
This commit is contained in:
mstrofnone
2026-05-03 17:23:53 +10:00
parent 3554ccf4c0
commit 737464e528
2 changed files with 41 additions and 0 deletions
@@ -99,6 +99,12 @@ val DEFAULT_ELECTRUMX_SERVERS =
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, usePinnedTrustStore = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, usePinnedTrustStore = true),
ElectrumxServer("46.229.238.187", 57002, useSsl = true, usePinnedTrustStore = true),
// relay.testls.bit — second public Namecoin ElectrumX deployment, served
// alongside the Namecoin-anchored Nostr relay at wss://relay.testls.bit/.
// TLS endpoint pinned to a self-signed cert (see PINNED_ELECTRUMX_CERTS).
// Also exposed as wss://relay.testls.bit/electrumx (browser-viable, future
// WS transport — see N1 §"Browser / WebSocket transport" in mstrofnone/nips).
ElectrumxServer("relay.testls.bit", 50002, useSsl = true, usePinnedTrustStore = true),
)
/** Tor-preferred server list: onion primary, clearnet fallback. */
@@ -110,6 +116,16 @@ val TOR_ELECTRUMX_SERVERS =
useSsl = true,
usePinnedTrustStore = true,
),
// relay.testls.bit — hidden service shared with the Nostr relay's onion.
// Plaintext over Tor (port 50001) since the onion key already authenticates
// the endpoint; TLS-on-Tor would only add round-trips with no security gain.
ElectrumxServer(
"6cbn4rskfdr647otej7gpqlmpqcmj723vg2eoeuu7ljbwu6cpdebozyd.onion",
50001,
useSsl = false,
usePinnedTrustStore = false,
),
ElectrumxServer("electrumx.testls.space", 50002, useSsl = true, usePinnedTrustStore = true),
ElectrumxServer("nmc2.bitcoins.sk", 57002, useSsl = true, usePinnedTrustStore = true),
ElectrumxServer("relay.testls.bit", 50002, useSsl = true, usePinnedTrustStore = true),
)
@@ -888,6 +888,31 @@ QXYftBo0HbtfsaJjImQdDjmlmRPSzE/RW6iUe+1cesKBC7e8nVf69Yu/fxO4m083
VWwAstlWJfk1GyU7jzVc8svealg/oIiDoOMe6CFSLx1BDv2FeHSpRdqd3fn+AC73
bK2N2smrHUOQnFijuiFw3WOrjERi0eMhjVNfVu9W9ZYa/Wd6SdIzV55LbG+NpmSf
5W7ix41hRvdT6cTAJA==
-----END CERTIFICATE-----
""".trimIndent(),
// relay.testls.bit:50002 — expires 2036-04-30
// Self-signed RSA-2048 cert (CN=relay.testls.bit) served by
// ElectrumX-NMC alongside the Namecoin-anchored Nostr relay.
// SHA-256 (DER): BB:0B:35:E6:42:35:A7:94:E1:57:B6:9A:CD:72:DA:4C:CC:16:A4:D8:1D:0F:F6:B1:D8:F7:FD:FC:6C:CA:6C:BA
"""
-----BEGIN CERTIFICATE-----
MIIDFzCCAf+gAwIBAgIUAz+Ky5Lu2u1QchHKTwQIStWD8fQwDQYJKoZIhvcNAQEL
BQAwGzEZMBcGA1UEAwwQcmVsYXkudGVzdGxzLmJpdDAeFw0yNjA1MDMwNjEyNDBa
Fw0zNjA0MzAwNjEyNDBaMBsxGTAXBgNVBAMMEHJlbGF5LnRlc3Rscy5iaXQwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCngMim0wilCdclMyIIBRAeFBjE
HWA0l5n3ebCtyepYmyXUrbth2TDdyMHiUNVvE3f7RSAUFtE+Tjb9+xzmLf04qlbC
i3b2DV3xdVOZpRCI4kybmraYG6lRLQJ5I/N8NWgPsFgcy2mZF3q0yMVEkzGAKqUT
QGZd2eBs/OVicbCWKmgyhXlnqGeHIs4iKOqenHKSZ8QE5bhAKaMn+Q116QEdBg12
svGNoSZSlX8hDNUf5N5pOcsK8vj0Yb0ypJOd0J5eVpYS/KA0oMMwALnEs0H17hfO
IIaWqrbfaqmdR67uzUfci2EoiwQJrXSy7WkNiVX0ikN02VlUPCb2OaSABmwjAgMB
AAGjUzBRMB0GA1UdDgQWBBSgnHYFU93wufP131xk5w843VWhATAfBgNVHSMEGDAW
gBSgnHYFU93wufP131xk5w843VWhATAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQAiVC5RJj/Y3S5uNYraPmRLQrgPui9eGlWDh6LeZvjftACA3WiN
XabJtTmHxOFFwxmBtzGVCWKR6udETHyfqaq0me/XoYLjGstYTd14GfoV9Klx7Glh
gLOgqC3Do04o2xnXxhPh00c0jUggKdI05KLVAc4dLfU/XDrOfxBl4XHZY4lYz4CF
bn+n5Q1cqqcGqoJIHl2cgDdrxSMigIpsunjk8cJXO+hsteA/Pd1UUY5plvE9nbNv
hy4QgfNqjy36b0Nbm7Fc9Te9W6zgXjHM+q7KhuQvTfKh2sHbCJzRcy7Chgwqyrfq
NsK0JcBkyRPB+fXmEoE/Xmj/UnOD0fZCCanD
-----END CERTIFICATE-----
""".trimIndent(),
)