From 0c885a89e1f3e2593c94639977e6cdd1504d476d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kyle=20=F0=9F=90=86?= Date: Thu, 16 Jul 2026 11:56:39 -0400 Subject: [PATCH 1/2] keep-desktop: enforce relay cert pinning on nostrconnect bunker start --- keep-desktop/src/nostrconnect.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/keep-desktop/src/nostrconnect.rs b/keep-desktop/src/nostrconnect.rs index 18924de8..bd129af4 100644 --- a/keep-desktop/src/nostrconnect.rs +++ b/keep-desktop/src/nostrconnect.rs @@ -87,9 +87,26 @@ impl App { let setup_arc = Arc::new(Mutex::new(None)); self.bunker_pending_setup = Some(setup_arc.clone()); let proxy = self.proxy_addr(); + let cert_pins = self.certificate_pins.clone(); + let keep_path = self.keep_path.clone(); + let require_pinned = self.settings.strict_cert_pinning; Task::perform( async move { + // Enforce/establish SPKI pins before starting the bunker against + // these relays. The relay list comes from the (attacker-influenceable) + // nostrconnect request, so this fails closed on a corrupt pin store + // or a pin mismatch, and records TOFU pins otherwise, mirroring the + // interactive bunker-start path in bunker_service.rs. + crate::frost::verify_relay_certificates( + &valid_relays, + &cert_pins, + &keep_path, + require_pinned, + ) + .await + .map_err(|e| format!("{e}"))?; + let keyring = tokio::task::spawn_blocking(move || extract_keyring(&keep_arc)) .await .map_err(|_| "Background task failed".to_string())??; From 9cf2649b5d3d587d6cc6fec42224bc2667848772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kyle=20=F0=9F=90=86?= Date: Thu, 16 Jul 2026 12:00:38 -0400 Subject: [PATCH 2/2] keep-desktop: preserve PinMismatch variant on nostrconnect cert failure --- keep-desktop/src/nostrconnect.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/keep-desktop/src/nostrconnect.rs b/keep-desktop/src/nostrconnect.rs index bd129af4..ca3fe995 100644 --- a/keep-desktop/src/nostrconnect.rs +++ b/keep-desktop/src/nostrconnect.rs @@ -98,14 +98,16 @@ impl App { // nostrconnect request, so this fails closed on a corrupt pin store // or a pin mismatch, and records TOFU pins otherwise, mirroring the // interactive bunker-start path in bunker_service.rs. + // Propagate the `ConnectionError` unchanged (via `?`) so a + // `PinMismatch` keeps its structured variant and reaches the + // dedicated cert-failure UI, matching the interactive path. crate::frost::verify_relay_certificates( &valid_relays, &cert_pins, &keep_path, require_pinned, ) - .await - .map_err(|e| format!("{e}"))?; + .await?; let keyring = tokio::task::spawn_blocking(move || extract_keyring(&keep_arc)) .await