commit 032280fc6a1e8b054c719f8fc3a54fa7a7c0418e
parent fae944f17be1400a5e0db3d3fd4e4e829d73c2ff
Author: triesap <tyson@radroots.org>
Date: Sun, 21 Jun 2026 20:23:18 +0000
events-codec: expand auth coverage
- Cover HTTP auth parsed wrappers, direct wrong-kind decode, invalid payload tags, and empty url or method validation.
- Cover relay auth parsed wrappers, direct wrong-kind decode, missing relay tags, empty relay tag values, and empty challenge validation.
- Validate focused auth tests, full radroots_events_codec tests, crate check, diff check, and refreshed coverage run.
Diffstat:
2 files changed, 166 insertions(+), 2 deletions(-)
diff --git a/crates/events_codec/src/http_auth/mod.rs b/crates/events_codec/src/http_auth/mod.rs
@@ -6,7 +6,7 @@ mod tests {
use radroots_events::{http_auth::RadrootsHttpAuth, kinds::KIND_POST};
use crate::error::{EventEncodeError, EventParseError};
- use crate::http_auth::decode::http_auth_from_event;
+ use crate::http_auth::decode::{data_from_event, http_auth_from_event, parsed_from_event};
use crate::http_auth::encode::{http_auth_build_tags, to_wire_parts, to_wire_parts_with_kind};
const PAYLOAD: &str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
@@ -82,6 +82,35 @@ mod tests {
EventEncodeError::InvalidField("payload_sha256")
));
+ let mut empty_url = auth.clone();
+ empty_url.url.clear();
+ let url_err = http_auth_build_tags(&empty_url).unwrap_err();
+ assert!(matches!(
+ url_err,
+ EventEncodeError::EmptyRequiredField("url")
+ ));
+
+ let mut empty_method = auth.clone();
+ empty_method.method.clear();
+ let method_err = http_auth_build_tags(&empty_method).unwrap_err();
+ assert!(matches!(
+ method_err,
+ EventEncodeError::EmptyRequiredField("method")
+ ));
+
+ let mut bad_payload_tag = parts.tags.clone();
+ replace_tag_value(&mut bad_payload_tag, "payload", "ABC");
+ let payload_tag_err = http_auth_from_event(parts.kind, &bad_payload_tag, "").unwrap_err();
+ assert!(matches!(
+ payload_tag_err,
+ EventParseError::InvalidTag("payload")
+ ));
+
+ let mut invalid_url = parts.tags.clone();
+ replace_tag_value(&mut invalid_url, "u", " ");
+ let url_tag_err = http_auth_from_event(parts.kind, &invalid_url, "").unwrap_err();
+ assert!(matches!(url_tag_err, EventParseError::InvalidTag("u")));
+
let content_err = http_auth_from_event(parts.kind, &parts.tags, "not empty").unwrap_err();
assert!(matches!(
content_err,
@@ -101,9 +130,64 @@ mod tests {
wrong_kind,
EventEncodeError::InvalidKind(KIND_POST)
));
+
+ let parts = to_wire_parts(&auth).expect("http auth wire parts");
+ let decode_wrong_kind = http_auth_from_event(KIND_POST, &parts.tags, "").unwrap_err();
+ assert!(matches!(
+ decode_wrong_kind,
+ EventParseError::InvalidKind {
+ expected: "27235",
+ got: KIND_POST
+ }
+ ));
+ }
+
+ #[test]
+ fn http_auth_wrappers_preserve_event_metadata() {
+ let auth = RadrootsHttpAuth {
+ url: "https://media.example.invalid/upload".to_string(),
+ method: "POST".to_string(),
+ payload_sha256: Some(PAYLOAD.to_string()),
+ };
+ let parts = to_wire_parts(&auth).expect("http auth wire parts");
+
+ let data = data_from_event(
+ "event-id".to_string(),
+ "author-pubkey".to_string(),
+ 99,
+ parts.kind,
+ parts.content.clone(),
+ parts.tags.clone(),
+ )
+ .expect("parsed data");
+ assert_eq!(data.id, "event-id");
+ assert_eq!(data.author, "author-pubkey");
+ assert_eq!(data.published_at, 99);
+ assert_eq!(data.data, auth);
+
+ let parsed = parsed_from_event(
+ "event-id".to_string(),
+ "author-pubkey".to_string(),
+ 99,
+ parts.kind,
+ parts.content,
+ parts.tags,
+ "sig".to_string(),
+ )
+ .expect("parsed event");
+ assert_eq!(parsed.event.sig, "sig");
+ assert_eq!(parsed.data.data, auth);
}
fn tag(key: &str, value: &str) -> Vec<String> {
vec![key.to_string(), value.to_string()]
}
+
+ fn replace_tag_value(tags: &mut [Vec<String>], key: &str, value: &str) {
+ let tag = tags
+ .iter_mut()
+ .find(|tag| tag.first().map(String::as_str) == Some(key))
+ .expect("tag");
+ tag[1] = value.to_string();
+ }
}
diff --git a/crates/events_codec/src/relay_auth/mod.rs b/crates/events_codec/src/relay_auth/mod.rs
@@ -6,7 +6,7 @@ mod tests {
use radroots_events::{kinds::KIND_POST, relay_auth::RadrootsRelayAuth};
use crate::error::{EventEncodeError, EventParseError};
- use crate::relay_auth::decode::relay_auth_from_event;
+ use crate::relay_auth::decode::{data_from_event, parsed_from_event, relay_auth_from_event};
use crate::relay_auth::encode::{
relay_auth_build_tags, to_wire_parts, to_wire_parts_with_kind,
};
@@ -33,6 +33,19 @@ mod tests {
#[test]
fn relay_auth_rejects_missing_challenge_non_empty_content_and_wrong_kind() {
let parts = to_wire_parts(&sample_auth()).expect("relay auth wire parts");
+ let without_relay = parts
+ .tags
+ .iter()
+ .filter(|tag| tag.first().map(|value| value.as_str()) != Some("relay"))
+ .cloned()
+ .collect::<Vec<_>>();
+ let missing_relay =
+ relay_auth_from_event(parts.kind, &without_relay, &parts.content).unwrap_err();
+ assert!(matches!(
+ missing_relay,
+ EventParseError::MissingTag("relay")
+ ));
+
let without_challenge = parts
.tags
.iter()
@@ -54,6 +67,15 @@ mod tests {
wrong_kind,
EventEncodeError::InvalidKind(KIND_POST)
));
+
+ let decode_wrong_kind = relay_auth_from_event(KIND_POST, &parts.tags, "").unwrap_err();
+ assert!(matches!(
+ decode_wrong_kind,
+ EventParseError::InvalidKind {
+ expected: "22242",
+ got: KIND_POST
+ }
+ ));
}
#[test]
@@ -65,6 +87,56 @@ mod tests {
relay_err,
EventEncodeError::EmptyRequiredField("relay")
));
+
+ let mut auth = sample_auth();
+ auth.challenge.clear();
+ let challenge_err = relay_auth_build_tags(&auth).unwrap_err();
+ assert!(matches!(
+ challenge_err,
+ EventEncodeError::EmptyRequiredField("challenge")
+ ));
+
+ let parts = to_wire_parts(&sample_auth()).expect("relay auth wire parts");
+ let mut empty_relay = parts.tags.clone();
+ replace_tag_value(&mut empty_relay, "relay", " ");
+ let relay_tag_err = relay_auth_from_event(parts.kind, &empty_relay, "").unwrap_err();
+ assert!(matches!(
+ relay_tag_err,
+ EventParseError::InvalidTag("relay")
+ ));
+ }
+
+ #[test]
+ fn relay_auth_wrappers_preserve_event_metadata() {
+ let auth = sample_auth();
+ let parts = to_wire_parts(&auth).expect("relay auth wire parts");
+
+ let data = data_from_event(
+ "event-id".to_string(),
+ "author-pubkey".to_string(),
+ 99,
+ parts.kind,
+ parts.content.clone(),
+ parts.tags.clone(),
+ )
+ .expect("parsed data");
+ assert_eq!(data.id, "event-id");
+ assert_eq!(data.author, "author-pubkey");
+ assert_eq!(data.published_at, 99);
+ assert_eq!(data.data, auth);
+
+ let parsed = parsed_from_event(
+ "event-id".to_string(),
+ "author-pubkey".to_string(),
+ 99,
+ parts.kind,
+ parts.content,
+ parts.tags,
+ "sig".to_string(),
+ )
+ .expect("parsed event");
+ assert_eq!(parsed.event.sig, "sig");
+ assert_eq!(parsed.data.data, auth);
}
fn sample_auth() -> RadrootsRelayAuth {
@@ -77,4 +149,12 @@ mod tests {
fn tag(key: &str, value: &str) -> Vec<String> {
vec![key.to_string(), value.to_string()]
}
+
+ fn replace_tag_value(tags: &mut [Vec<String>], key: &str, value: &str) {
+ let tag = tags
+ .iter_mut()
+ .find(|tag| tag.first().map(String::as_str) == Some(key))
+ .expect("tag");
+ tag[1] = value.to_string();
+ }
}