protocol.rs (1988B)
1 #![forbid(unsafe_code)] 2 3 use crate::host_nostr::{Keys, PublicKey}; 4 use nostr::nips::nip46::NostrConnectMessage; 5 use nostr::{Event, EventBuilder}; 6 7 /// Encrypts and locally signs a NIP-46 transport message. 8 /// 9 /// The completed event is returned for transport-only publication. NIP-46 10 /// kind 24133 is protocol traffic, not a generic Radroots product-authoring 11 /// surface. 12 pub(crate) fn sign_nip46_message( 13 sender_keys: &Keys, 14 receiver_pubkey: PublicKey, 15 message: NostrConnectMessage, 16 ) -> Result<Event, nostr::event::builder::Error> { 17 EventBuilder::nostr_connect(sender_keys, receiver_pubkey, message)?.sign_with_keys(sender_keys) 18 } 19 20 #[cfg(test)] 21 mod tests { 22 use crate::host_nostr::{Keys, Kind}; 23 use nostr::JsonUtil; 24 use nostr::nips::{nip44, nip46::NostrConnectRequest}; 25 26 use super::sign_nip46_message; 27 28 #[test] 29 fn signed_nip46_message_is_bound_to_sender_and_receiver() { 30 let sender = Keys::generate(); 31 let receiver = Keys::generate(); 32 let message = nostr::nips::nip46::NostrConnectMessage::request(&NostrConnectRequest::Ping); 33 let request_id = message.id().to_owned(); 34 35 let event = sign_nip46_message(&sender, receiver.public_key(), message) 36 .expect("signed NIP-46 message"); 37 38 assert_eq!(event.kind, Kind::NostrConnect); 39 assert_eq!(event.pubkey, sender.public_key()); 40 assert!( 41 event 42 .tags 43 .iter() 44 .any(|tag| { tag.as_slice() == ["p".to_owned(), receiver.public_key().to_hex()] }) 45 ); 46 assert!(event.verify().is_ok()); 47 48 let plaintext = nip44::decrypt(receiver.secret_key(), &sender.public_key(), &event.content) 49 .expect("decrypt NIP-46 message"); 50 let decrypted = nostr::nips::nip46::NostrConnectMessage::from_json(plaintext) 51 .expect("parse NIP-46 message"); 52 assert!(decrypted.is_request()); 53 assert_eq!(decrypted.id(), request_id); 54 } 55 }