commit d46c0d9003acf19bb42c69c259f7b01a00b0403b
parent c78040fecf4fc4352567d7a42e676911c1d0e1ea
Author: triesap <tyson@radroots.org>
Date: Sat, 21 Mar 2026 17:35:56 +0000
web: add browser-signer disconnect action
- expose a disconnect action only when a NIP-07 browser signer is connected
- clear the app-owned browser signer session and return the web app to setup
- keep signer key custody external to the app instead of exposing native-only destructive actions
- validate the web lane with the wasm toolchain helper and trunk build
Diffstat:
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/crates/web/src/lib.rs b/crates/web/src/lib.rs
@@ -14,7 +14,10 @@ use nostr::signer::NostrSigner;
#[cfg(target_arch = "wasm32")]
use nostr_browser_signer::{BrowserSigner, Error as BrowserSignerError};
#[cfg(target_arch = "wasm32")]
-use radroots_app_core::{IdentityGateState, RadrootsApp, RadrootsAppBackend, SetupActionState};
+use radroots_app_core::{
+ HomeActionKind, HomeActionState, IdentityGateState, RadrootsApp, RadrootsAppBackend,
+ SetupActionState,
+};
#[cfg(target_arch = "wasm32")]
#[derive(Clone)]
@@ -70,6 +73,13 @@ impl WebBackend {
other => format!("Browser signer connection failed: {other}"),
}
}
+
+ fn disconnect_signer(&self) -> IdentityGateState {
+ let mut state = self.state.borrow_mut();
+ state.connection = WebConnectionState::Disconnected;
+ state.pending_result = None;
+ IdentityGateState::Missing
+ }
}
#[cfg(target_arch = "wasm32")]
@@ -145,6 +155,29 @@ impl RadrootsAppBackend for WebBackend {
Ok(None)
}
+ fn home_action_states(&self) -> Vec<HomeActionState> {
+ let state = self.state.borrow();
+ match &state.connection {
+ WebConnectionState::Ready(_) => vec![HomeActionState {
+ kind: HomeActionKind::DisconnectSigner,
+ label: "Disconnect Browser Signer".to_owned(),
+ enabled: true,
+ pending: false,
+ }],
+ WebConnectionState::Disconnected | WebConnectionState::Connecting => Vec::new(),
+ }
+ }
+
+ fn request_home_action(
+ &self,
+ action: HomeActionKind,
+ ) -> Result<Option<IdentityGateState>, String> {
+ match action {
+ HomeActionKind::DisconnectSigner => Ok(Some(self.disconnect_signer())),
+ HomeActionKind::RemoveLocalKey | HomeActionKind::ResetDevice => Ok(None),
+ }
+ }
+
fn poll_identity_state(&self) -> Result<Option<IdentityGateState>, String> {
let mut state = self.state.borrow_mut();
let Some(result) = state.pending_result.take() else {