lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

draft_signing.rs (4143B)


      1 #![forbid(unsafe_code)]
      2 
      3 use crate::error::RadrootsNostrError;
      4 use crate::event_convert::radroots_event_from_nostr;
      5 use crate::events::radroots_nostr_build_event;
      6 use crate::types::{RadrootsNostrKeys, RadrootsNostrTimestamp};
      7 use nostr::JsonUtil;
      8 use radroots_events::draft::{RadrootsFrozenEventDraft, RadrootsSignedNostrEvent};
      9 
     10 pub fn radroots_nostr_sign_frozen_draft(
     11     keys: &RadrootsNostrKeys,
     12     draft: &RadrootsFrozenEventDraft,
     13 ) -> Result<RadrootsSignedNostrEvent, RadrootsNostrError> {
     14     let actual_pubkey = keys.public_key().to_hex();
     15     if actual_pubkey != draft.expected_pubkey {
     16         return Err(RadrootsNostrError::FrozenDraftPubkeyMismatch {
     17             expected_pubkey: draft.expected_pubkey.clone(),
     18             actual_pubkey,
     19         });
     20     }
     21 
     22     let event = radroots_nostr_build_event(draft.kind, draft.content.clone(), draft.tags.clone())?
     23         .custom_created_at(RadrootsNostrTimestamp::from_secs(u64::from(
     24             draft.created_at,
     25         )))
     26         .sign_with_keys(keys)?;
     27     let actual_event_id = event.id.to_hex();
     28     if actual_event_id != draft.expected_event_id {
     29         return Err(RadrootsNostrError::FrozenDraftEventIdMismatch {
     30             expected_event_id: draft.expected_event_id.clone(),
     31             actual_event_id,
     32         });
     33     }
     34 
     35     let raw_json = event.as_json();
     36     RadrootsSignedNostrEvent::from_event(radroots_event_from_nostr(&event), raw_json)
     37         .map_err(Into::into)
     38 }
     39 
     40 #[cfg(test)]
     41 mod tests {
     42     use super::radroots_nostr_sign_frozen_draft;
     43     use crate::error::RadrootsNostrError;
     44     use crate::test_fixtures::{FIXTURE_ALICE, FIXTURE_BOB};
     45     use crate::types::{RadrootsNostrKeys, RadrootsNostrSecretKey};
     46     use nostr::JsonUtil;
     47     use radroots_events::draft::RadrootsFrozenEventDraft;
     48     use radroots_events::kinds::KIND_POST;
     49 
     50     fn fixture_keys(secret_key_hex: &str) -> RadrootsNostrKeys {
     51         let secret_key = RadrootsNostrSecretKey::from_hex(secret_key_hex).expect("secret key");
     52         RadrootsNostrKeys::new(secret_key)
     53     }
     54 
     55     fn post_draft(expected_pubkey: &str) -> RadrootsFrozenEventDraft {
     56         RadrootsFrozenEventDraft::new(
     57             "radroots.social.post.v1",
     58             KIND_POST,
     59             1_700_000_000,
     60             vec![vec!["t".to_owned(), "soil".to_owned()]],
     61             "hello",
     62             expected_pubkey,
     63         )
     64         .expect("draft")
     65     }
     66 
     67     #[test]
     68     fn sign_frozen_draft_uses_fixed_created_at_and_expected_id() {
     69         let keys = fixture_keys(FIXTURE_ALICE.secret_key_hex);
     70         let draft = post_draft(FIXTURE_ALICE.public_key_hex);
     71         let signed = radroots_nostr_sign_frozen_draft(&keys, &draft).expect("signed event");
     72 
     73         assert_eq!(signed.id, draft.expected_event_id);
     74         assert_eq!(signed.pubkey, draft.expected_pubkey);
     75         assert_eq!(signed.created_at, draft.created_at);
     76         assert_eq!(signed.kind, draft.kind);
     77         assert_eq!(signed.tags, draft.tags);
     78         assert_eq!(signed.content, draft.content);
     79 
     80         let raw_event = crate::types::RadrootsNostrEvent::from_json(signed.raw_json.as_str())
     81             .expect("raw json");
     82         assert_eq!(raw_event.id.to_hex(), signed.id);
     83         assert_eq!(raw_event.created_at.as_secs(), u64::from(draft.created_at));
     84     }
     85 
     86     #[test]
     87     fn sign_frozen_draft_rejects_wrong_signer() {
     88         let keys = fixture_keys(FIXTURE_BOB.secret_key_hex);
     89         let draft = post_draft(FIXTURE_ALICE.public_key_hex);
     90         let error = radroots_nostr_sign_frozen_draft(&keys, &draft).expect_err("wrong signer");
     91 
     92         assert!(matches!(
     93             error,
     94             RadrootsNostrError::FrozenDraftPubkeyMismatch { .. }
     95         ));
     96     }
     97 
     98     #[test]
     99     fn sign_frozen_draft_rejects_event_id_mismatch() {
    100         let keys = fixture_keys(FIXTURE_ALICE.secret_key_hex);
    101         let mut draft = post_draft(FIXTURE_ALICE.public_key_hex);
    102         draft.expected_event_id = "f".repeat(64);
    103         let error = radroots_nostr_sign_frozen_draft(&keys, &draft).expect_err("id mismatch");
    104 
    105         assert!(matches!(
    106             error,
    107             RadrootsNostrError::FrozenDraftEventIdMismatch { .. }
    108         ));
    109     }
    110 }