1use hmac::Hmac;
11use serde::{Deserialize, Serialize};
12use sha2::Sha256;
13
14pub mod nonce;
15pub mod storage {
16 pub use crate::nonce::storage::*;
18}
19
20pub use nonce::{NonceClient, NonceConfig, NonceError, NonceServer};
22
23type HmacSha256 = Hmac<Sha256>;
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct NonceCredential {
38 pub timestamp: u64,
39 pub nonce: String,
40 pub signature: String,
41}
42
43#[cfg(test)]
44mod tests {
45 use crate::nonce::{NonceClient, NonceError, NonceServer};
46
47 #[tokio::test]
48 async fn test_client_server_separation() {
49 let client = NonceClient::new(b"test_secret");
50 let server = NonceServer::builder().build_and_init().await.unwrap();
51 let payload = b"test_payload";
52
53 let credential = client.credential_builder().sign(payload).unwrap();
55
56 let result = server
58 .credential_verifier(&credential)
59 .with_secret(b"test_secret")
60 .verify(payload)
61 .await;
62
63 assert!(result.is_ok());
64
65 let result = server
67 .credential_verifier(&credential)
68 .with_secret(b"test_secret")
69 .verify(payload)
70 .await;
71
72 assert!(matches!(result, Err(NonceError::DuplicateNonce)));
73 }
74
75 #[tokio::test]
76 async fn test_context_isolation() {
77 let client = NonceClient::new(b"test_secret");
78 let server = NonceServer::builder().build_and_init().await.unwrap();
79 let payload = b"test_payload";
80
81 let credential = client.credential_builder().sign(payload).unwrap();
82
83 server
85 .credential_verifier(&credential)
86 .with_secret(b"test_secret")
87 .with_context(Some("context1"))
88 .verify(payload)
89 .await
90 .unwrap();
91
92 server
93 .credential_verifier(&credential)
94 .with_secret(b"test_secret")
95 .with_context(Some("context2"))
96 .verify(payload)
97 .await
98 .unwrap();
99
100 let result = server
102 .credential_verifier(&credential)
103 .with_secret(b"test_secret")
104 .with_context(Some("context1"))
105 .verify(payload)
106 .await;
107
108 assert!(matches!(result, Err(NonceError::DuplicateNonce)));
109 }
110
111 #[tokio::test]
112 async fn test_timestamp_validation() {
113 let client = NonceClient::new(b"test_secret");
114 let server = NonceServer::builder()
115 .with_time_window(std::time::Duration::from_secs(1))
116 .build_and_init()
117 .await
118 .unwrap();
119 let payload = b"test_payload";
120
121 let mut credential = client.credential_builder().sign(payload).unwrap();
123
124 credential.timestamp = std::time::SystemTime::now()
126 .duration_since(std::time::UNIX_EPOCH)
127 .unwrap()
128 .as_secs()
129 - 2;
130
131 let result = server
132 .credential_verifier(&credential)
133 .with_secret(b"test_secret")
134 .verify(payload)
135 .await;
136
137 assert!(matches!(result, Err(NonceError::TimestampOutOfWindow)));
138 }
139
140 #[tokio::test]
141 async fn test_signature_verification() {
142 let client = NonceClient::new(b"test_secret");
143 let server = NonceServer::builder().build_and_init().await.unwrap();
144 let payload = b"test_payload";
145
146 let credential = client.credential_builder().sign(payload).unwrap();
147
148 let result = server
149 .credential_verifier(&credential)
150 .with_secret(b"different_secret") .verify(payload)
152 .await;
153
154 assert!(matches!(result, Err(NonceError::InvalidSignature)));
155 }
156
157 #[tokio::test]
158 async fn test_serialization() {
159 let client = NonceClient::new(b"test_secret");
160 let credential = client.credential_builder().sign(b"test_payload").unwrap();
161
162 let json = serde_json::to_string(&credential).unwrap();
164 let deserialized: super::NonceCredential = serde_json::from_str(&json).unwrap();
165
166 assert_eq!(credential.timestamp, deserialized.timestamp);
167 assert_eq!(credential.nonce, deserialized.nonce);
168 assert_eq!(credential.signature, deserialized.signature);
169 }
170}