admission.rs (4070B)
1 use core::fmt; 2 3 use radroots_event::{ 4 contract::{EventContract, event_contract}, 5 envelope::EventEnvelope, 6 envelope::kind::KIND_PROFILE, 7 }; 8 9 use crate::profile::inbound::{ 10 RadrootsInboundProfileMetadata, RadrootsProfileMetadataParseError, 11 parse_inbound_profile_metadata, 12 }; 13 use crate::verification::{ 14 RadrootsNip01VerificationError, RadrootsSignatureVerifiedEvent, verify_nip01_event, 15 }; 16 17 /// A verified kind-0 event bound to its tolerant metadata projection. 18 #[derive(Clone, Debug, PartialEq)] 19 pub struct RadrootsAdmittedProfileEvent { 20 verified_event: RadrootsSignatureVerifiedEvent, 21 metadata: RadrootsInboundProfileMetadata, 22 } 23 24 impl RadrootsAdmittedProfileEvent { 25 pub fn verified_event(&self) -> &RadrootsSignatureVerifiedEvent { 26 &self.verified_event 27 } 28 29 pub fn event(&self) -> &EventEnvelope { 30 self.verified_event.event() 31 } 32 33 pub fn metadata(&self) -> &RadrootsInboundProfileMetadata { 34 &self.metadata 35 } 36 37 pub fn contract(&self) -> &'static EventContract { 38 event_contract("radroots.profile.metadata.v1") 39 .expect("Profile metadata contract is registry-owned") 40 } 41 42 pub fn into_parts( 43 self, 44 ) -> ( 45 RadrootsSignatureVerifiedEvent, 46 RadrootsInboundProfileMetadata, 47 ) { 48 (self.verified_event, self.metadata) 49 } 50 } 51 52 #[non_exhaustive] 53 #[derive(Clone, Debug, PartialEq, Eq)] 54 pub enum RadrootsProfileAdmissionError { 55 Nip01Verification(RadrootsNip01VerificationError), 56 InvalidKind { expected: u32, actual: u32 }, 57 Metadata(RadrootsProfileMetadataParseError), 58 } 59 60 impl RadrootsProfileAdmissionError { 61 pub const fn code(&self) -> &'static str { 62 match self { 63 Self::Nip01Verification(error) => error.code(), 64 Self::InvalidKind { .. } => "invalid_kind", 65 Self::Metadata(error) => error.code(), 66 } 67 } 68 } 69 70 impl fmt::Display for RadrootsProfileAdmissionError { 71 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 72 match self { 73 Self::Nip01Verification(error) => write!(formatter, "{error}"), 74 Self::InvalidKind { expected, actual } => { 75 write!( 76 formatter, 77 "Profile event kind must be {expected}, got {actual}" 78 ) 79 } 80 Self::Metadata(error) => write!(formatter, "{error}"), 81 } 82 } 83 } 84 85 #[cfg(feature = "std")] 86 impl std::error::Error for RadrootsProfileAdmissionError { 87 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 88 match self { 89 Self::Nip01Verification(error) => Some(error), 90 Self::Metadata(error) => Some(error), 91 Self::InvalidKind { .. } => None, 92 } 93 } 94 } 95 96 impl From<RadrootsNip01VerificationError> for RadrootsProfileAdmissionError { 97 fn from(value: RadrootsNip01VerificationError) -> Self { 98 Self::Nip01Verification(value) 99 } 100 } 101 102 impl From<RadrootsProfileMetadataParseError> for RadrootsProfileAdmissionError { 103 fn from(value: RadrootsProfileMetadataParseError) -> Self { 104 Self::Metadata(value) 105 } 106 } 107 108 /// Admits an already verified Profile event and preserves its exact envelope. 109 pub fn admit_verified_profile_event( 110 verified_event: RadrootsSignatureVerifiedEvent, 111 ) -> Result<RadrootsAdmittedProfileEvent, RadrootsProfileAdmissionError> { 112 let actual = verified_event.event().kind_u32(); 113 if actual != KIND_PROFILE { 114 return Err(RadrootsProfileAdmissionError::InvalidKind { 115 expected: KIND_PROFILE, 116 actual, 117 }); 118 } 119 let metadata = parse_inbound_profile_metadata(verified_event.event().content())?; 120 Ok(RadrootsAdmittedProfileEvent { 121 verified_event, 122 metadata, 123 }) 124 } 125 126 /// Verifies id and signature before parsing and admitting exact kind-0 content. 127 pub fn verify_and_admit_profile_event( 128 event: EventEnvelope, 129 ) -> Result<RadrootsAdmittedProfileEvent, RadrootsProfileAdmissionError> { 130 admit_verified_profile_event(verify_nip01_event(event)?) 131 }