Add protected chapter

This commit is contained in:
Jon Staab
2026-05-20 12:27:22 -07:00
parent f0d49c6fb8
commit 8ad0bc393b
8 changed files with 675 additions and 5 deletions
+125
View File
@@ -0,0 +1,125 @@
use coracle_lib::events::{EventContent, HashedEvent};
use coracle_lib::keys::SecretKey;
use coracle_lib::protected::is_protected;
use coracle_lib::tags::{Tag, Tags};
fn fixed_secret() -> SecretKey {
let bytes: [u8; 32] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32,
];
SecretKey::from_hex(&hex::encode(bytes)).unwrap()
}
fn build_hashed(tags: Tags) -> HashedEvent {
EventContent::new()
.content("hi")
.tags(tags)
.kind(1)
.stamp(1_700_000_000)
.own(fixed_secret().public_key())
.hash()
}
// --- Tag::protected constructor ---
#[test]
fn tag_constructor_shape() {
let t = Tag::protected();
assert_eq!(t.name(), "-");
assert_eq!(t.len(), 1);
assert!(t.values().is_empty());
}
#[test]
fn tag_constructor_serializes_as_single_element() {
let t = Tag::protected();
assert_eq!(serde_json::to_string(&t).unwrap(), r#"["-"]"#);
}
// --- is_protected ---
#[test]
fn is_protected_false_when_tag_absent() {
let tags = Tags::new();
assert!(!is_protected(&tags));
}
#[test]
fn is_protected_false_with_unrelated_tags() {
let tags = Tags::from(vec![Tag::new("t", ["nostr"]), Tag::expiration(100)]);
assert!(!is_protected(&tags));
}
#[test]
fn is_protected_true_when_tag_present() {
let tags = Tags::from(vec![Tag::protected()]);
assert!(is_protected(&tags));
}
#[test]
fn is_protected_true_among_other_tags() {
let tags = Tags::from(vec![
Tag::new("t", ["nostr"]),
Tag::protected(),
Tag::expiration(100),
]);
assert!(is_protected(&tags));
}
#[test]
fn is_protected_detects_a_raw_dash_tag() {
// The marker is identified by name alone; a hand-built ["-"] is
// equivalent to Tag::protected().
let tags = Tags::from(vec![Tag::new("-", Vec::<String>::new())]);
assert!(is_protected(&tags));
}
// --- HashedEvent method facade ---
#[test]
fn hashed_event_reports_protected() {
let event = build_hashed(Tags::from(vec![Tag::protected()]));
assert!(event.is_protected());
}
#[test]
fn hashed_event_reports_unprotected() {
let event = build_hashed(Tags::new());
assert!(!event.is_protected());
}
// --- Event method facade ---
#[test]
fn signed_event_reports_protected() {
let sk = fixed_secret();
let hashed = build_hashed(Tags::from(vec![Tag::protected()]));
let sig = sk.sign(&hashed.id);
let signed = hashed.sign(sig);
assert!(signed.is_protected());
}
#[test]
fn protected_tag_survives_hashing_and_signing() {
// The tag is part of the canonical hash input, so it must round-trip
// through hash() and sign() intact and still verify.
let sk = fixed_secret();
let hashed = build_hashed(Tags::from(vec![Tag::protected()]));
let sig = sk.sign(&hashed.id);
let signed = hashed.sign(sig);
assert!(signed.verify_id());
assert!(signed.is_protected());
}
#[test]
fn unprotected_event_stays_unprotected_through_signing() {
let sk = fixed_secret();
let hashed = build_hashed(Tags::new());
let sig = sk.sign(&hashed.id);
let signed = hashed.sign(sig);
assert!(!signed.is_protected());
}