auths_id/identity/
events.rs1use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct KeyRotationEvent {
16 pub sequence: u64,
18
19 pub previous_hash: String,
22
23 #[serde(with = "base64_bytes")]
25 pub old_public_key: Vec<u8>,
26
27 #[serde(with = "base64_bytes")]
29 pub new_public_key: Vec<u8>,
30
31 pub timestamp: DateTime<Utc>,
33
34 #[serde(with = "base64_bytes")]
37 pub rotation_signature: Vec<u8>,
38}
39
40impl KeyRotationEvent {
41 pub fn new(
43 sequence: u64,
44 previous_hash: String,
45 old_public_key: Vec<u8>,
46 new_public_key: Vec<u8>,
47 timestamp: DateTime<Utc>,
48 rotation_signature: Vec<u8>,
49 ) -> Self {
50 Self {
51 sequence,
52 previous_hash,
53 old_public_key,
54 new_public_key,
55 timestamp,
56 rotation_signature,
57 }
58 }
59
60 pub fn canonical_bytes_for_signing(&self) -> Vec<u8> {
65 let mut data = Vec::new();
67 data.extend_from_slice(&self.sequence.to_be_bytes());
68 data.extend_from_slice(self.previous_hash.as_bytes());
69 data.extend_from_slice(&self.old_public_key);
70 data.extend_from_slice(&self.new_public_key);
71 data.extend_from_slice(self.timestamp.to_rfc3339().as_bytes());
72 data
73 }
74}
75
76mod base64_bytes {
78 use base64::{Engine as _, engine::general_purpose::STANDARD};
79 use serde::{Deserialize, Deserializer, Serializer};
80
81 pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
82 where
83 S: Serializer,
84 {
85 serializer.serialize_str(&STANDARD.encode(bytes))
86 }
87
88 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
89 where
90 D: Deserializer<'de>,
91 {
92 let s = String::deserialize(deserializer)?;
93 STANDARD.decode(&s).map_err(serde::de::Error::custom)
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use chrono::TimeZone;
101
102 #[test]
103 fn test_key_rotation_event_serialization() {
104 let timestamp = Utc.with_ymd_and_hms(2026, 1, 15, 12, 0, 0).unwrap();
105 let event = KeyRotationEvent::new(
106 1,
107 "abc123hash".to_string(),
108 vec![1u8; 32], vec![2u8; 32], timestamp,
111 vec![3u8; 64], );
113
114 let json = serde_json::to_string(&event).expect("Failed to serialize");
115 let deserialized: KeyRotationEvent =
116 serde_json::from_str(&json).expect("Failed to deserialize");
117
118 assert_eq!(event, deserialized);
119 assert_eq!(deserialized.sequence, 1);
120 assert_eq!(deserialized.previous_hash, "abc123hash");
121 assert_eq!(deserialized.old_public_key, vec![1u8; 32]);
122 assert_eq!(deserialized.new_public_key, vec![2u8; 32]);
123 assert_eq!(deserialized.rotation_signature, vec![3u8; 64]);
124 }
125
126 #[test]
127 fn test_canonical_bytes_for_signing() {
128 let timestamp = Utc.with_ymd_and_hms(2026, 1, 15, 12, 0, 0).unwrap();
129 let event = KeyRotationEvent::new(
130 1,
131 "prevhash".to_string(),
132 vec![0u8; 32],
133 vec![1u8; 32],
134 timestamp,
135 vec![],
136 );
137
138 let bytes = event.canonical_bytes_for_signing();
139 assert!(!bytes.is_empty());
140
141 let bytes2 = event.canonical_bytes_for_signing();
143 assert_eq!(bytes, bytes2);
144 }
145}