nip09_deletion_request_profile.rs (4228B)
1 mod support; 2 3 use nostr::{Keys as RadrootsNostrKeys, SecretKey as RadrootsNostrSecretKey}; 4 use radroots_event::{ 5 envelope::kind::KIND_DELETION_REQUEST, 6 post::deletion::{ 7 AuthoredNip09DeletionRequest, Nip09DeletionAddressTarget, Nip09DeletionEventTarget, 8 }, 9 }; 10 use radroots_event_codec::admission::deletion::verify_and_admit_nip09_deletion_request_event; 11 use radroots_nostr::Error; 12 use radroots_nostr::event::Kind as RadrootsNostrKind; 13 use radroots_nostr::event::Timestamp as RadrootsNostrTimestamp; 14 use radroots_nostr::event::from_nostr; 15 use radroots_nostr::event::{ 16 GenericBuilder, build_nip09_deletion_request as build_nip09_deletion_request_event, 17 }; 18 use support::{FIXTURE_ALICE_SECRET_KEY_HEX, FIXTURE_BOB_PUBLIC_KEY_HEX}; 19 20 const CREATED_AT: u64 = 1_784_347_200; 21 const TARGET_EVENT_ID: &str = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; 22 23 #[test] 24 fn typed_nip09_deletion_request_signs_exact_tags_and_admits() { 25 let request = request(); 26 let created_at = RadrootsNostrTimestamp::from_secs(CREATED_AT); 27 let profile_coordinate = format!("0:{FIXTURE_BOB_PUBLIC_KEY_HEX}:"); 28 let listing_coordinate = format!("30402:{FIXTURE_BOB_PUBLIC_KEY_HEX}:carrots"); 29 let expected_tags = vec![ 30 tag(&["e", TARGET_EVENT_ID]), 31 tag(&["a", &profile_coordinate]), 32 tag(&["a", &listing_coordinate]), 33 tag(&["k", "0"]), 34 tag(&["k", "1"]), 35 tag(&["k", "30402"]), 36 ]; 37 38 let event = build_nip09_deletion_request_event(&request) 39 .expect("typed NIP-09 builder") 40 .custom_created_at(created_at) 41 .sign_with_keys(&fixture_keys()) 42 .expect("signed NIP-09 deletion request"); 43 44 assert_eq!(event.kind.as_u16(), KIND_DELETION_REQUEST as u16); 45 assert_eq!(event.created_at, created_at); 46 assert_eq!(event.content, "superseded"); 47 assert_eq!(event_tags(&event), expected_tags); 48 event.verify().expect("valid deletion-request signature"); 49 50 let admitted = verify_and_admit_nip09_deletion_request_event( 51 from_nostr(&event).expect("deletion-request event adapter"), 52 ) 53 .expect("deletion-request admission"); 54 assert_eq!( 55 admitted.contract().id, 56 "radroots.social.deletion_request.v1" 57 ); 58 assert_eq!(admitted.projection().event_targets().len(), 1); 59 assert_eq!(admitted.projection().address_targets().len(), 2); 60 assert_eq!( 61 admitted 62 .projection() 63 .kind_advisories() 64 .iter() 65 .map(|advisory| advisory.kind()) 66 .collect::<Vec<_>>(), 67 vec![0, 1, 30_402] 68 ); 69 assert!(admitted.projection().diagnostics().is_empty()); 70 assert_eq!(admitted.projection().raw_tags(), expected_tags.as_slice()); 71 } 72 73 #[test] 74 fn generic_kind_five_builder_cannot_bypass_typed_deletion_authoring() { 75 let error = GenericBuilder::new( 76 RadrootsNostrKind::Custom(KIND_DELETION_REQUEST as u16), 77 "Raw deletion request", 78 ) 79 .sign_with_keys(&fixture_keys()) 80 .expect_err("every generic kind 5 must be reserved"); 81 82 assert!(matches!( 83 error, 84 Error::TypedAuthoringRequired { kind } 85 if kind == KIND_DELETION_REQUEST as u16 86 )); 87 } 88 89 fn request() -> AuthoredNip09DeletionRequest { 90 AuthoredNip09DeletionRequest::new( 91 "superseded", 92 vec![Nip09DeletionEventTarget::parse(TARGET_EVENT_ID, 1).expect("event target")], 93 vec![ 94 Nip09DeletionAddressTarget::parse(format!( 95 "30402:{FIXTURE_BOB_PUBLIC_KEY_HEX}:carrots" 96 )) 97 .expect("listing target"), 98 Nip09DeletionAddressTarget::parse(format!("0:{FIXTURE_BOB_PUBLIC_KEY_HEX}:")) 99 .expect("profile target"), 100 ], 101 ) 102 .expect("authored deletion request") 103 } 104 105 fn fixture_keys() -> RadrootsNostrKeys { 106 RadrootsNostrKeys::new( 107 RadrootsNostrSecretKey::from_hex(FIXTURE_ALICE_SECRET_KEY_HEX).expect("fixture secret key"), 108 ) 109 } 110 111 fn event_tags(event: &nostr::Event) -> Vec<Vec<String>> { 112 event 113 .tags 114 .iter() 115 .map(|tag| tag.as_slice().to_vec()) 116 .collect() 117 } 118 119 fn tag(values: &[&str]) -> Vec<String> { 120 values.iter().map(|value| (*value).to_owned()).collect() 121 }