mod.rs (7017B)
1 pub mod decode; 2 pub mod encode; 3 4 #[cfg(test)] 5 mod tests { 6 use radroots_events::{http_auth::RadrootsHttpAuth, kinds::KIND_POST}; 7 8 use crate::error::{EventEncodeError, EventParseError}; 9 use crate::http_auth::decode::{data_from_event, http_auth_from_event, parsed_from_event}; 10 use crate::http_auth::encode::{http_auth_build_tags, to_wire_parts, to_wire_parts_with_kind}; 11 12 const PAYLOAD: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; 13 14 #[test] 15 fn http_auth_encodes_and_decodes_get_without_payload() { 16 let auth = RadrootsHttpAuth { 17 url: "https://media.example.invalid/download".to_string(), 18 method: "GET".to_string(), 19 payload_sha256: None, 20 }; 21 let parts = to_wire_parts(&auth).expect("http auth wire parts"); 22 23 assert_eq!(parts.kind, 27235); 24 assert_eq!(parts.content, ""); 25 assert!(parts.tags.contains(&tag("u", auth.url.as_str()))); 26 assert!(parts.tags.contains(&tag("method", "GET"))); 27 28 let decoded = 29 http_auth_from_event(parts.kind, &parts.tags, &parts.content).expect("decode"); 30 assert_eq!(decoded, auth); 31 } 32 33 #[test] 34 fn http_auth_encodes_and_decodes_post_with_payload() { 35 let auth = RadrootsHttpAuth { 36 url: "https://media.example.invalid/upload".to_string(), 37 method: "POST".to_string(), 38 payload_sha256: Some(PAYLOAD.to_string()), 39 }; 40 let parts = to_wire_parts(&auth).expect("http auth wire parts"); 41 42 assert!(parts.tags.contains(&tag("payload", PAYLOAD))); 43 let decoded = 44 http_auth_from_event(parts.kind, &parts.tags, &parts.content).expect("decode"); 45 assert_eq!(decoded.payload_sha256.as_deref(), Some(PAYLOAD)); 46 } 47 48 #[test] 49 fn http_auth_rejects_missing_url_missing_method_bad_payload_and_content() { 50 let auth = RadrootsHttpAuth { 51 url: "https://media.example.invalid/upload".to_string(), 52 method: "POST".to_string(), 53 payload_sha256: Some(PAYLOAD.to_string()), 54 }; 55 let parts = to_wire_parts(&auth).expect("http auth wire parts"); 56 let without_url = parts 57 .tags 58 .iter() 59 .filter(|tag| tag.first().map(|value| value.as_str()) != Some("u")) 60 .cloned() 61 .collect::<Vec<_>>(); 62 let missing_url = http_auth_from_event(parts.kind, &without_url, "").unwrap_err(); 63 assert!(matches!(missing_url, EventParseError::MissingTag("u"))); 64 65 let without_method = parts 66 .tags 67 .iter() 68 .filter(|tag| tag.first().map(|value| value.as_str()) != Some("method")) 69 .cloned() 70 .collect::<Vec<_>>(); 71 let missing_method = http_auth_from_event(parts.kind, &without_method, "").unwrap_err(); 72 assert!(matches!( 73 missing_method, 74 EventParseError::MissingTag("method") 75 )); 76 77 let mut bad_payload = auth.clone(); 78 bad_payload.payload_sha256 = Some("ABC".to_string()); 79 let payload_err = http_auth_build_tags(&bad_payload).unwrap_err(); 80 assert!(matches!( 81 payload_err, 82 EventEncodeError::InvalidField("payload_sha256") 83 )); 84 85 let mut empty_url = auth.clone(); 86 empty_url.url.clear(); 87 let url_err = http_auth_build_tags(&empty_url).unwrap_err(); 88 assert!(matches!( 89 url_err, 90 EventEncodeError::EmptyRequiredField("url") 91 )); 92 93 let mut empty_method = auth.clone(); 94 empty_method.method.clear(); 95 let method_err = http_auth_build_tags(&empty_method).unwrap_err(); 96 assert!(matches!( 97 method_err, 98 EventEncodeError::EmptyRequiredField("method") 99 )); 100 101 let mut bad_payload_tag = parts.tags.clone(); 102 replace_tag_value(&mut bad_payload_tag, "payload", "ABC"); 103 let payload_tag_err = http_auth_from_event(parts.kind, &bad_payload_tag, "").unwrap_err(); 104 assert!(matches!( 105 payload_tag_err, 106 EventParseError::InvalidTag("payload") 107 )); 108 109 let mut invalid_url = parts.tags.clone(); 110 replace_tag_value(&mut invalid_url, "u", " "); 111 let url_tag_err = http_auth_from_event(parts.kind, &invalid_url, "").unwrap_err(); 112 assert!(matches!(url_tag_err, EventParseError::InvalidTag("u"))); 113 114 let content_err = http_auth_from_event(parts.kind, &parts.tags, "not empty").unwrap_err(); 115 assert!(matches!( 116 content_err, 117 EventParseError::InvalidJson("content") 118 )); 119 } 120 121 #[test] 122 fn http_auth_rejects_wrong_kind() { 123 let auth = RadrootsHttpAuth { 124 url: "https://media.example.invalid/upload".to_string(), 125 method: "POST".to_string(), 126 payload_sha256: Some(PAYLOAD.to_string()), 127 }; 128 let wrong_kind = to_wire_parts_with_kind(&auth, KIND_POST).unwrap_err(); 129 assert!(matches!( 130 wrong_kind, 131 EventEncodeError::InvalidKind(KIND_POST) 132 )); 133 134 let parts = to_wire_parts(&auth).expect("http auth wire parts"); 135 let decode_wrong_kind = http_auth_from_event(KIND_POST, &parts.tags, "").unwrap_err(); 136 assert!(matches!( 137 decode_wrong_kind, 138 EventParseError::InvalidKind { 139 expected: "27235", 140 got: KIND_POST 141 } 142 )); 143 } 144 145 #[test] 146 fn http_auth_wrappers_preserve_event_metadata() { 147 let auth = RadrootsHttpAuth { 148 url: "https://media.example.invalid/upload".to_string(), 149 method: "POST".to_string(), 150 payload_sha256: Some(PAYLOAD.to_string()), 151 }; 152 let parts = to_wire_parts(&auth).expect("http auth wire parts"); 153 154 let data = data_from_event( 155 "event-id".to_string(), 156 "author-pubkey".to_string(), 157 99, 158 parts.kind, 159 parts.content.clone(), 160 parts.tags.clone(), 161 ) 162 .expect("parsed data"); 163 assert_eq!(data.id, "event-id"); 164 assert_eq!(data.author, "author-pubkey"); 165 assert_eq!(data.published_at, 99); 166 assert_eq!(data.data, auth); 167 168 let parsed = parsed_from_event( 169 "event-id".to_string(), 170 "author-pubkey".to_string(), 171 99, 172 parts.kind, 173 parts.content, 174 parts.tags, 175 "sig".to_string(), 176 ) 177 .expect("parsed event"); 178 assert_eq!(parsed.event.sig, "sig"); 179 assert_eq!(parsed.data.data, auth); 180 } 181 182 fn tag(key: &str, value: &str) -> Vec<String> { 183 vec![key.to_string(), value.to_string()] 184 } 185 186 fn replace_tag_value(tags: &mut [Vec<String>], key: &str, value: &str) { 187 let tag = tags 188 .iter_mut() 189 .find(|tag| tag.first().map(String::as_str) == Some(key)) 190 .expect("tag"); 191 tag[1] = value.to_string(); 192 } 193 }