1use anyhow::Result;
7use bytes::{Buf as _, Bytes};
8
9#[derive(Debug, Clone)]
11pub struct Claims {
12 pub realm_id: u32,
14
15 pub key_id: u32,
17 pub token: Bytes,
19}
20
21impl Claims {
22 pub fn new(realm_id: u32, key_id: u32, token: Bytes) -> Self {
23 Self {
24 realm_id,
25 key_id,
26 token,
27 }
28 }
29
30 pub fn encode(&self) -> String {
47 let mut buffer = Vec::new();
48
49 buffer.extend_from_slice(&self.realm_id.to_be_bytes());
51
52 buffer.extend_from_slice(&self.key_id.to_be_bytes());
54
55 buffer.extend_from_slice(&self.token);
57
58 base122::encode(&buffer)
60 }
61
62 pub fn decode(s: &str) -> Result<Self> {
74 let bytes =
76 base122::decode(s).map_err(|e| anyhow::anyhow!("Failed to decode base122: {}", e))?;
77
78 if bytes.len() < 8 {
80 return Err(anyhow::anyhow!("Invalid username length: too short"));
81 }
82
83 let mut buf = bytes.as_slice();
84
85 if buf.remaining() < 4 {
87 return Err(anyhow::anyhow!(
88 "Invalid format: insufficient bytes for realm_id"
89 ));
90 }
91 let realm_id = buf.get_u32();
92
93 if buf.remaining() < 4 {
95 return Err(anyhow::anyhow!(
96 "Invalid format: insufficient bytes for key_id"
97 ));
98 }
99 let key_id = buf.get_u32();
100
101 let token = Bytes::from(buf.to_vec());
103
104 Ok(Claims {
105 realm_id,
106 key_id,
107 token,
108 })
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_claims_new() {
118 let token_bytes = Bytes::from(b"test_token".as_slice());
119 let claims = Claims::new(123, 456, token_bytes.clone());
120
121 assert_eq!(claims.realm_id, 123);
122 assert_eq!(claims.key_id, 456);
123 assert_eq!(claims.token, token_bytes);
124 }
125
126 #[test]
127 fn test_claims_encode_decode() {
128 let token_bytes = Bytes::from(b"test_token_data".as_slice());
129 let claims = Claims::new(12345, 67890, token_bytes.clone());
130
131 let encoded = claims.encode();
133 assert!(!encoded.is_empty());
134
135 let decoded = Claims::decode(&encoded).expect("Failed to decode");
137 assert_eq!(decoded.realm_id, 12345);
138 assert_eq!(decoded.key_id, 67890);
139 assert_eq!(decoded.token, token_bytes);
140 }
141
142 #[test]
143 fn test_claims_encode_decode_empty_token() {
144 let token_bytes = Bytes::from(b"".as_slice());
145 let claims = Claims::new(1, 2, token_bytes.clone());
146
147 let encoded = claims.encode();
148 let decoded = Claims::decode(&encoded).expect("Failed to decode");
149
150 assert_eq!(decoded.realm_id, 1);
151 assert_eq!(decoded.key_id, 2);
152 assert_eq!(decoded.token, token_bytes);
153 }
154
155 #[test]
156 fn test_claims_encode_decode_large_values() {
157 let token_bytes = Bytes::from(vec![0x01, 0x02, 0x03, 0x04, 0x05]);
158 let claims = Claims::new(u32::MAX, u32::MAX, token_bytes.clone());
159
160 let encoded = claims.encode();
161 let decoded = Claims::decode(&encoded).expect("Failed to decode");
162
163 assert_eq!(decoded.realm_id, u32::MAX);
164 assert_eq!(decoded.key_id, u32::MAX);
165 assert_eq!(decoded.token, token_bytes);
166 }
167
168 #[test]
169 fn test_claims_decode_invalid_short_string() {
170 let short_encoded = base122::encode(&[1, 2, 3, 4, 5, 6, 7]); let result = Claims::decode(&short_encoded);
174 assert!(result.is_err());
175 assert!(
176 result
177 .unwrap_err()
178 .to_string()
179 .contains("Invalid username length")
180 );
181 }
182
183 #[test]
184 fn test_claims_decode_invalid_base122() {
185 let result = Claims::decode("a"); match result {
190 Ok(decoded) => {
191 assert!(decoded.token.len() < 1000); }
196 Err(e) => {
197 let err_msg = e.to_string();
199 assert!(
200 err_msg.contains("Invalid username length")
201 || err_msg.contains("Failed to decode base122")
202 || err_msg.contains("insufficient bytes"),
203 "Unexpected error message: {}",
204 err_msg
205 );
206 }
207 }
208 }
209
210 #[test]
211 fn test_claims_encode_decode_roundtrip_multiple() {
212 let test_cases = vec![
213 (0u32, 0u32, b"".as_slice()),
214 (1u32, 1u32, b"a".as_slice()),
215 (100u32, 200u32, b"hello".as_slice()),
216 (999u32, 888u32, b"world".as_slice()),
217 (12345u32, 67890u32, b"test_token_data_12345".as_slice()),
218 ];
219
220 for (realm_id, key_id, token_data) in test_cases {
221 let token_bytes = Bytes::from(token_data);
222 let claims = Claims::new(realm_id, key_id, token_bytes.clone());
223
224 let encoded = claims.encode();
225 let decoded = Claims::decode(&encoded).expect("Failed to decode");
226
227 assert_eq!(
228 decoded.realm_id, realm_id,
229 "realm_id mismatch for test case: realm_id={}, key_id={}",
230 realm_id, key_id
231 );
232 assert_eq!(
233 decoded.key_id, key_id,
234 "key_id mismatch for test case: realm_id={}, key_id={}",
235 realm_id, key_id
236 );
237 assert_eq!(
238 decoded.token, token_bytes,
239 "token mismatch for test case: realm_id={}, key_id={}",
240 realm_id, key_id
241 );
242 }
243 }
244
245 #[test]
246 fn test_claims_byte_layout_verification() {
247 let token_bytes = Bytes::from(b"token".as_slice());
249 let claims = Claims::new(0x12345678, 0xABCDEF00, token_bytes);
250
251 let encoded = claims.encode();
252 let decoded_bytes = base122::decode(&encoded).expect("Failed to decode base122");
253
254 assert!(decoded_bytes.len() >= 8);
256
257 let realm_id_bytes = &decoded_bytes[0..4];
259 let realm_id = u32::from_be_bytes([
260 realm_id_bytes[0],
261 realm_id_bytes[1],
262 realm_id_bytes[2],
263 realm_id_bytes[3],
264 ]);
265 assert_eq!(realm_id, 0x12345678);
266
267 let key_id_bytes = &decoded_bytes[4..8];
269 let key_id = u32::from_be_bytes([
270 key_id_bytes[0],
271 key_id_bytes[1],
272 key_id_bytes[2],
273 key_id_bytes[3],
274 ]);
275 assert_eq!(key_id, 0xABCDEF00);
276 }
277}