From c789cb478442557231024b1d52232e0a24e84927 Mon Sep 17 00:00:00 2001 From: Avi Date: Tue, 22 Sep 2026 20:39:30 -0500 Subject: [PATCH] fix(pairing): drop purplepag.es and nostr.band from the pairing relay set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live write+readback canary (Sep 22): purplepag.es rejects kind 24133 outright ('blocked: kind 24133 is not allowed') and relay.nostr.band hangs the WebSocket handshake. A signer (Amber) that picks a blocking relay reports 'connected' while its connect event is silently discarded — exactly the observed failure. The Sep 22 18:01 trace shows a pairing window that opened, never saw an inbound 24133, and timed out; a post-hoc relay sweep found zero 24133 events tagged to the ephemeral key on any relay, consistent with Amber's write being rejected. Replaced with nos.lol and relay.snort.social, both verified to accept and serve ephemeral kind-24133. Added a regression test pinning the blockers out of the set. --- src/relays.rs | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/relays.rs b/src/relays.rs index 3a6ecfb..1ed4dde 100644 --- a/src/relays.rs +++ b/src/relays.rs @@ -20,12 +20,22 @@ pub fn default_relays() -> Vec { /// reliability for ephemeral kind-24133 traffic; listening on a few extra /// well-known relays costs nothing and makes pairing robust whichever one /// the signer happens to choose. +/// +/// This set was curated with a live write+readback canary (Sep 22, 2026): +/// - wss://purplepag.es REJECTS kind 24133 ("blocked: kind 24133 is not +/// allowed") — a signer that picks it reports "connected" while its +/// connect event is thrown away, so it must never be in the pairing URI. +/// - wss://relay.nostr.band currently hangs the WebSocket handshake; it is +/// also pay-to-read. Dropped from the pairing set. +/// - wss://nos.lol and wss://relay.snort.social accept ephemeral 24133 and +/// serve it live (snort does not persist ephemeral kinds, which is fine — +/// pairing only needs the live push). pub fn pairing_relays() -> Vec { vec![ "wss://relay.damus.io".to_string(), "wss://relay.primal.net".to_string(), - "wss://purplepag.es".to_string(), - "wss://relay.nostr.band".to_string(), + "wss://nos.lol".to_string(), + "wss://relay.snort.social".to_string(), ] } @@ -195,6 +205,25 @@ mod tests { assert!(relays.iter().all(|r| r.enabled)); } + #[test] + fn pairing_relays_exclude_24133_blockers() { + // purplepag.es returns "blocked: kind 24133 is not allowed" and + // relay.nostr.band hangs the handshake (canary, Sep 22 2026). A + // signer that picks a blocking relay says "connected" while its + // connect event is discarded, so neither may appear in the URI. + let relays = pairing_relays(); + assert!(!relays.iter().any(|r| r.contains("purplepag"))); + assert!(!relays.iter().any(|r| r.contains("nostr.band"))); + // Every entry is a well-formed wss URL and the set is deduped. + for url in &relays { + validate_url(url).expect("pairing relay must be a valid wss URL"); + } + let mut sorted = relays.clone(); + sorted.sort(); + sorted.dedup(); + assert_eq!(sorted.len(), relays.len()); + } + #[test] fn validate_url_accepts_wss_and_ws() { assert!(validate_url("wss://relay.example.com").is_ok());