radrootsd

JSON-RPC bridge for Radroots event publishing
git clone https://radroots.dev/git/radrootsd.git
Log | Files | Refs | README | LICENSE

commit 33764d271dbb54801efa635eb6b0ee0bacee5989
parent e2b57f62f094701d6d7d4bd006b4b138ba8ef883
Author: triesap <tyson@radroots.org>
Date:   Sun, 29 Mar 2026 02:15:40 +0000

bridge: stabilize nip46 idempotency identity

Diffstat:
Msrc/transport/jsonrpc/methods/bridge/shared.rs | 48++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/src/transport/jsonrpc/methods/bridge/shared.rs b/src/transport/jsonrpc/methods/bridge/shared.rs @@ -179,7 +179,6 @@ pub(super) fn normalize_idempotency_key(value: Option<String>) -> Result<Option< #[derive(Serialize)] struct BridgeRequestFingerprint<'a, T> { command: &'a str, - signer_mode: &'a str, signer_pubkey_hex: &'a str, payload: &'a T, } @@ -191,7 +190,6 @@ pub(super) fn fingerprint_bridge_request<T: Serialize>( ) -> Result<String, RpcError> { let payload = serde_json::to_vec(&BridgeRequestFingerprint { command, - signer_mode: &signer.signer_mode(), signer_pubkey_hex: &signer.signer_pubkey_hex(), payload, }) @@ -309,6 +307,52 @@ mod tests { } #[test] + fn fingerprint_bridge_request_is_stable_across_nip46_session_renewal() { + let session_keys = RadrootsNostrKeys::generate(); + let session = Nip46Session { + id: "session-1".to_string(), + client: RadrootsNostrClient::new(session_keys.clone()), + client_keys: RadrootsNostrKeys::generate(), + client_pubkey: RadrootsNostrKeys::generate().public_key(), + remote_signer_pubkey: session_keys.public_key(), + user_pubkey: None, + relays: vec!["wss://relay.example.com".to_string()], + perms: vec!["sign_event".to_string()], + name: None, + url: None, + image: None, + expires_at: None, + auth_required: false, + authorized: true, + auth_url: None, + pending_request: None, + }; + let renewed_session = Nip46Session { + id: "session-2".to_string(), + ..session.clone() + }; + let first = fingerprint_bridge_request( + "bridge.order.request", + &super::BridgeSignerSelection::Nip46Session { + session_id: "session-1".to_string(), + session, + }, + &serde_json::json!({"order_id":"same"}), + ) + .expect("first"); + let second = fingerprint_bridge_request( + "bridge.order.request", + &super::BridgeSignerSelection::Nip46Session { + session_id: "session-2".to_string(), + session: renewed_session, + }, + &serde_json::json!({"order_id":"same"}), + ) + .expect("second"); + assert_eq!(first, second); + } + + #[test] fn bridge_job_view_exposes_terminal_and_recovery_flags() { let mut job = new_listing_publish_job( "job-1".to_string(),