1#![allow(unused_imports)]
2
3use crate::{Email, IdenticationRequirement, TokenBundle};
4use crate::{LightMPAATHeader, LightMPAATPayload, LightMPAATSignature, MPAATHeader, MPAATPayload, MPAATSignature};
5use crate::{MResult, ServerError};
6
7#[cfg(any(feature = "pqc-utils", feature = "ed25519-utils"))]
8use crate::SignKeypair;
9
10#[cfg(feature = "crypt-utils")]
11use crate::CipherKey;
12
13pub fn base64_encode(data: &[u8]) -> String {
15 use base64::{Engine as _, engine::general_purpose::URL_SAFE};
16 URL_SAFE.encode(data)
17}
18
19pub fn base64_decode(data: &str) -> MResult<Vec<u8>> {
21 use base64::{Engine as _, engine::general_purpose::URL_SAFE};
22 URL_SAFE.decode(data).map_err(ServerError::from_private)
23}
24
25pub fn generate<const SZ: usize>() -> [u8; SZ] {
27 use rand::Rng;
28
29 let mut arr: [u8; SZ] = [0; SZ];
30 let mut rng = rand::rng();
31 rng.fill(arr.as_mut_slice());
32 arr
33}
34
35#[cfg(all(
36 feature = "crypt-utils",
37 feature = "authnz-utils",
38 any(feature = "pqc-utils", feature = "ed25519-utils")
39))]
40pub fn deploy_mpaat<U: serde::Serialize, T: serde::Serialize>(
42 payload: T,
43 common_fields: Option<U>,
44 exp: chrono::DateTime<chrono::Utc>,
45 client_public: &[u8],
46 server_enc: Option<&CipherKey>,
47 server_keys: &SignKeypair,
48) -> MResult<String> {
49 use base64::{
50 Engine as _,
51 engine::general_purpose::{STANDARD, URL_SAFE},
52 };
53 use impulse_server_kit::tracing;
54
55 tracing::debug!("MPAAT (deploy): Got client public: {:?}", client_public);
56 tracing::debug!("MPAAT (deploy): Expires at: {:?}", exp);
57
58 let payload = MPAATPayload {
59 cli_pkey: client_public.to_vec(),
60 exp,
61 container: payload,
62 };
63 let (enc_payload, nonce) = if let Some(server_enc) = server_enc {
64 tracing::debug!("MPAAT (deploy): Encrypting with a `ekey`...");
65 server_enc.encrypt(&payload).map_err(|e| {
66 ServerError::from_private(e)
67 .with_private_str("Can't encrypt payload with `server_enc` key!")
68 .with_500()
69 })?
70 } else {
71 tracing::debug!("MPAAT (deploy): Skip encryption...");
72 (
73 rmp_serde::to_vec(&payload).map_err(|e| {
74 ServerError::from_private(e)
75 .with_private_str("Can't serialize MPAAT payload!")
76 .with_500()
77 })?,
78 vec![],
79 )
80 };
81
82 let header = MPAATHeader {
83 authnz_pkey: server_keys.public(),
84 nonce,
85 common_public_fields: common_fields,
86 };
87
88 let sig = header.sign_mpaat(&enc_payload, server_keys).map_err(|e| {
89 ServerError::from_private(e)
90 .with_private_str("Can't sign MPAAT with server keyring!")
91 .with_500()
92 })?;
93 tracing::debug!("MPAAT (deploy): Signature: {:?}", sig);
94
95 let sig = MPAATSignature { sig };
96 let sig = STANDARD.encode(rmp_serde::to_vec(&sig).map_err(|e| {
97 ServerError::from_private(e)
98 .with_private_str("Can't serialize MPAAT signature!")
99 .with_500()
100 })?);
101
102 let header = STANDARD.encode(rmp_serde::to_vec(&header).map_err(|e| {
103 ServerError::from_private(e)
104 .with_private_str("Can't serialize MPAAT header!")
105 .with_500()
106 })?);
107 let enc_payload = URL_SAFE.encode(&enc_payload);
108
109 Ok(format!("{enc_payload}.{sig}.{header}"))
110}
111
112#[cfg(all(
113 feature = "crypt-utils",
114 feature = "authnz-utils",
115 any(feature = "pqc-utils", feature = "ed25519-utils")
116))]
117pub fn deploy_lmpaat<U: serde::Serialize, T: serde::Serialize>(
119 payload: T,
120 common_fields: Option<U>,
121 exp: chrono::DateTime<chrono::Utc>,
122 client_public: &[u8],
123 server_keys: &SignKeypair,
124) -> MResult<String> {
125 use base64::{
126 Engine as _,
127 engine::general_purpose::{STANDARD, URL_SAFE},
128 };
129 use impulse_server_kit::tracing;
130
131 tracing::debug!("LMPAAT (deploy): Got client public: {:?}", client_public);
132 tracing::debug!("LMPAAT (deploy): Expires at: {:?}", exp);
133
134 let payload = LightMPAATPayload { exp, container: payload };
135 let enc_payload = rmp_serde::to_vec(&payload).map_err(|e| {
136 ServerError::from_private(e)
137 .with_private_str("Can't serialize LMPAAT payload!")
138 .with_500()
139 })?;
140 let enc_payload = URL_SAFE.encode(&enc_payload);
141
142 let header = LightMPAATHeader {
143 cli_pkey: client_public.to_vec(),
144 common_public_fields: common_fields,
145 };
146
147 let sig = header.sign_lmpaat(&payload, server_keys).map_err(|e| {
148 ServerError::from_private(e)
149 .with_private_str("Can't sign LMPAAT header!")
150 .with_500()
151 })?;
152 tracing::debug!("LMPAAT (deploy): Signature: {:?}", sig);
153
154 let sig = MPAATSignature { sig };
155 let sig = STANDARD.encode(rmp_serde::to_vec(&sig).map_err(|e| {
156 ServerError::from_private(e)
157 .with_private_str("Can't serialize LMPAAT signature!")
158 .with_500()
159 })?);
160
161 let header = STANDARD.encode(rmp_serde::to_vec(&header).map_err(|e| {
162 ServerError::from_private(e)
163 .with_private_str("Can't serialize LMPAAT header!")
164 .with_500()
165 })?);
166
167 Ok(format!("{enc_payload}.{sig}.{header}"))
168}
169
170#[cfg(all(
171 feature = "crypt-utils",
172 feature = "authnz-utils",
173 any(feature = "pqc-utils", feature = "ed25519-utils")
174))]
175pub fn mpaat_extract_common_fields<U: serde::de::DeserializeOwned>(token: &str, server_keys: &SignKeypair) -> MResult<Option<U>> {
177 use base64::{
178 Engine as _,
179 engine::general_purpose::{STANDARD, URL_SAFE},
180 };
181 use impulse_server_kit::tracing;
182
183 let parts = token.split('.').collect::<Vec<_>>();
184
185 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
186 let sig = STANDARD.decode(sig).map_err(|e| {
187 ServerError::from_private(e)
188 .with_private_str("Can't decode MPAAT signature!")
189 .with_500()
190 })?;
191 let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
192 ServerError::from_private(e)
193 .with_private_str("Can't deserialize MPAAT signature!")
194 .with_500()
195 })?;
196
197 tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
198
199 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
200 let payload = URL_SAFE.decode(payload).map_err(|e| {
201 ServerError::from_private(e)
202 .with_private_str("Can't decode MPAAT payload!")
203 .with_500()
204 })?;
205
206 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
207 let header = STANDARD.decode(header).map_err(|e| {
208 ServerError::from_private(e)
209 .with_private_str("Can't decode MPAAT header!")
210 .with_500()
211 })?;
212
213 let authnz_pkey = server_keys.public();
214
215 SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
216 ServerError::from_private(e)
217 .with_private_str("Token is unverified!")
218 .with_public("Invalid token signature, consider to sign in again.")
219 .with_401()
220 })?;
221
222 let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
223 ServerError::from_private(e)
224 .with_private_str("Can't deserialize MPAAT header!")
225 .with_500()
226 })?;
227 if header.authnz_pkey != authnz_pkey.as_slice() {
228 return Err(
229 ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
230 .with_public("Invalid token signature, consider to sign in again.")
231 .with_401(),
232 );
233 }
234
235 Ok(header.common_public_fields)
236}
237
238#[cfg(all(
239 feature = "crypt-utils",
240 feature = "authnz-utils",
241 any(feature = "pqc-utils", feature = "ed25519-utils")
242))]
243pub fn mpaat_extract_payload<T, U>(
247 token: &str,
248 server_enc: Option<&CipherKey>,
249 server_keys: &SignKeypair,
250 current_dt: chrono::DateTime<chrono::Utc>,
251) -> MResult<T>
252where
253 T: serde::de::DeserializeOwned,
254 U: serde::de::DeserializeOwned,
255{
256 use base64::{
257 Engine as _,
258 engine::general_purpose::{STANDARD, URL_SAFE},
259 };
260 use impulse_server_kit::tracing;
261
262 let parts = token.split('.').collect::<Vec<_>>();
263
264 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
265 let sig = STANDARD.decode(sig).map_err(|e| {
266 ServerError::from_private(e)
267 .with_private_str("Can't decode MPAAT signature!")
268 .with_500()
269 })?;
270 let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
271 ServerError::from_private(e)
272 .with_private_str("Can't deserialize MPAAT signature!")
273 .with_500()
274 })?;
275
276 tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
277
278 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
279 let payload = URL_SAFE.decode(payload).map_err(|e| {
280 ServerError::from_private(e)
281 .with_private_str("Can't decode MPAAT payload!")
282 .with_500()
283 })?;
284
285 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
286 let header = STANDARD.decode(header).map_err(|e| {
287 ServerError::from_private(e)
288 .with_private_str("Can't decode MPAAT header!")
289 .with_500()
290 })?;
291
292 let authnz_pkey = server_keys.public();
293
294 SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
295 ServerError::from_private(e)
296 .with_private_str("Token is unverified!")
297 .with_public("Invalid token signature, consider to sign in again.")
298 .with_401()
299 })?;
300
301 let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
302 ServerError::from_private(e)
303 .with_private_str("Can't deserialize MPAAT header!")
304 .with_500()
305 })?;
306 if header.authnz_pkey != authnz_pkey.as_slice() {
307 return Err(
308 ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
309 .with_public("Invalid token signature, consider to sign in again.")
310 .with_401(),
311 );
312 }
313
314 let payload = if let Some(server_enc) = server_enc {
315 tracing::debug!("MPAAT: Decrypting with given `ekey`...");
316 server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
317 ServerError::from_private(e)
318 .with_private_str("Can't decrypt payload with given `server_enc` key!")
319 .with_public("Invalid token, consider to sign in again.")
320 .with_401()
321 })?
322 } else {
323 tracing::debug!("MPAAT: Skip decryption...");
324 rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
325 ServerError::from_private(e)
326 .with_private_str("Can't deserialize payload!")
327 .with_public("Invalid token, consider to sign in again.")
328 .with_401()
329 })?
330 };
331
332 tracing::debug!("MPAAT: Expires at: {:?}", payload.exp);
333
334 if current_dt >= payload.exp {
335 return Err(
336 ServerError::from_private_str("Token is expired!")
337 .with_public("Invalid token, consider to sign in again.")
338 .with_401(),
339 );
340 }
341
342 Ok(payload.container)
343}
344
345#[cfg(all(
346 feature = "crypt-utils",
347 feature = "authnz-utils",
348 any(feature = "pqc-utils", feature = "ed25519-utils")
349))]
350pub fn mpaat_extract_payload_with_metadata<T, U>(
354 token: &str,
355 server_enc: Option<&CipherKey>,
356 server_keys: &SignKeypair,
357 current_dt: chrono::DateTime<chrono::Utc>,
358) -> MResult<MPAATPayload<T>>
359where
360 T: serde::de::DeserializeOwned,
361 U: serde::de::DeserializeOwned,
362{
363 use base64::{
364 Engine as _,
365 engine::general_purpose::{STANDARD, URL_SAFE},
366 };
367 use impulse_server_kit::tracing;
368
369 let parts = token.split('.').collect::<Vec<_>>();
370
371 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
372 let sig = STANDARD.decode(sig).map_err(|e| {
373 ServerError::from_private(e)
374 .with_private_str("Can't decode MPAAT signature!")
375 .with_500()
376 })?;
377 let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
378 ServerError::from_private(e)
379 .with_private_str("Can't deserialize MPAAT signature!")
380 .with_500()
381 })?;
382
383 tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
384
385 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
386 let payload = URL_SAFE.decode(payload).map_err(|e| {
387 ServerError::from_private(e)
388 .with_private_str("Can't decode MPAAT payload!")
389 .with_500()
390 })?;
391
392 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
393 let header = STANDARD.decode(header).map_err(|e| {
394 ServerError::from_private(e)
395 .with_private_str("Can't decode MPAAT header!")
396 .with_500()
397 })?;
398
399 let authnz_pkey = server_keys.public();
400
401 SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
402 ServerError::from_private(e)
403 .with_private_str("Token is unverified!")
404 .with_public("Invalid token signature, consider to sign in again.")
405 .with_401()
406 })?;
407
408 let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
409 ServerError::from_private(e)
410 .with_private_str("Can't deserialize MPAAT header!")
411 .with_500()
412 })?;
413 if header.authnz_pkey != authnz_pkey.as_slice() {
414 return Err(
415 ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
416 .with_public("Invalid token signature, consider to sign in again.")
417 .with_401(),
418 );
419 }
420
421 let payload = if let Some(server_enc) = server_enc {
422 tracing::debug!("MPAAT: Decrypting with given `ekey`...");
423 server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
424 ServerError::from_private(e)
425 .with_private_str("Can't decrypt payload with given `server_enc` key!")
426 .with_public("Invalid token, consider to sign in again.")
427 .with_401()
428 })?
429 } else {
430 tracing::debug!("MPAAT: Skip decryption...");
431 rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
432 ServerError::from_private(e)
433 .with_private_str("Can't deserialize payload!")
434 .with_public("Invalid token, consider to sign in again.")
435 .with_401()
436 })?
437 };
438
439 tracing::debug!("MPAAT: Expires at: {:?}", payload.exp);
440
441 if current_dt >= payload.exp {
442 return Err(
443 ServerError::from_private_str("Token is expired!")
444 .with_public("Invalid token, consider to sign in again.")
445 .with_401(),
446 );
447 }
448
449 Ok(payload)
450}
451
452#[cfg(all(
453 feature = "crypt-utils",
454 feature = "authnz-utils",
455 any(feature = "pqc-utils", feature = "ed25519-utils")
456))]
457pub fn mpaat_extract_payload_with_metadata_exp_ignored<T, U>(
461 token: &str,
462 server_enc: Option<&CipherKey>,
463 server_keys: &SignKeypair,
464) -> MResult<MPAATPayload<T>>
465where
466 T: serde::de::DeserializeOwned,
467 U: serde::de::DeserializeOwned,
468{
469 use base64::{
470 Engine as _,
471 engine::general_purpose::{STANDARD, URL_SAFE},
472 };
473 use impulse_server_kit::tracing;
474
475 let parts = token.split('.').collect::<Vec<_>>();
476
477 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
478 let sig = STANDARD.decode(sig).map_err(|e| {
479 ServerError::from_private(e)
480 .with_private_str("Can't decode MPAAT signature!")
481 .with_500()
482 })?;
483 let sig = rmp_serde::from_slice::<MPAATSignature>(&sig).map_err(|e| {
484 ServerError::from_private(e)
485 .with_private_str("Can't deserialize MPAAT signature!")
486 .with_500()
487 })?;
488
489 tracing::debug!("MPAAT: Got signature: {:?}", sig.sig);
490
491 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
492 let payload = URL_SAFE.decode(payload).map_err(|e| {
493 ServerError::from_private(e)
494 .with_private_str("Can't decode MPAAT payload!")
495 .with_500()
496 })?;
497
498 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
499 let header = STANDARD.decode(header).map_err(|e| {
500 ServerError::from_private(e)
501 .with_private_str("Can't decode MPAAT header!")
502 .with_500()
503 })?;
504
505 let authnz_pkey = server_keys.public();
506
507 SignKeypair::verify_token(&header, &payload, &sig.sig, &authnz_pkey).map_err(|e| {
508 ServerError::from_private(e)
509 .with_private_str("Token is unverified!")
510 .with_public("Invalid token signature, consider to sign in again.")
511 .with_401()
512 })?;
513
514 let header = rmp_serde::from_slice::<MPAATHeader<U>>(&header).map_err(|e| {
515 ServerError::from_private(e)
516 .with_private_str("Can't deserialize MPAAT header!")
517 .with_500()
518 })?;
519 if header.authnz_pkey != authnz_pkey.as_slice() {
520 return Err(
521 ServerError::from_private_str("Header's C3A public key and actual C3A public key are not equal!")
522 .with_public("Invalid token signature, consider to sign in again.")
523 .with_401(),
524 );
525 }
526
527 let payload = if let Some(server_enc) = server_enc {
528 tracing::debug!("MPAAT: Decrypting with given `ekey`...");
529 server_enc.decrypt::<MPAATPayload<T>>(&payload, &header.nonce).map_err(|e| {
530 ServerError::from_private(e)
531 .with_private_str("Can't decrypt payload with given `server_enc` key!")
532 .with_public("Invalid token, consider to sign in again.")
533 .with_401()
534 })?
535 } else {
536 tracing::debug!("MPAAT: Skip decryption...");
537 rmp_serde::from_slice::<MPAATPayload<T>>(&payload).map_err(|e| {
538 ServerError::from_private(e)
539 .with_private_str("Can't deserialize payload!")
540 .with_public("Invalid token, consider to sign in again.")
541 .with_401()
542 })?
543 };
544
545 Ok(payload)
546}
547
548#[cfg(all(
549 feature = "crypt-utils",
550 feature = "authnz-utils",
551 any(feature = "pqc-utils", feature = "ed25519-utils")
552))]
553pub fn lmpaat_extract_common_fields<U: serde::de::DeserializeOwned>(token: &str, server_keys: &SignKeypair) -> MResult<Option<U>> {
555 use base64::{
556 Engine as _,
557 engine::general_purpose::{STANDARD, URL_SAFE},
558 };
559 use impulse_server_kit::tracing;
560
561 let parts = token.split('.').collect::<Vec<_>>();
562
563 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
564 let sig = STANDARD.decode(sig).map_err(|e| {
565 ServerError::from_private(e)
566 .with_private_str("Can't decode LMPAAT signature!")
567 .with_500()
568 })?;
569 let sig = rmp_serde::from_slice::<LightMPAATSignature>(&sig).map_err(|e| {
570 ServerError::from_private(e)
571 .with_private_str("Can't deserialize LMPAAT signature!")
572 .with_500()
573 })?;
574
575 tracing::debug!("LMPAAT: Got signature: {:?}", sig.sig);
576
577 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
578 let payload = URL_SAFE.decode(payload).map_err(|e| {
579 ServerError::from_private(e)
580 .with_private_str("Can't decode LMPAAT payload!")
581 .with_500()
582 })?;
583
584 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
585 let header = STANDARD.decode(header).map_err(|e| {
586 ServerError::from_private(e)
587 .with_private_str("Can't decode LMPAAT header!")
588 .with_500()
589 })?;
590
591 SignKeypair::verify_token(&header, &payload, &sig.sig, &server_keys.public()).map_err(|e| {
592 ServerError::from_private(e)
593 .with_private_str("LMPAAT token is unverified!")
594 .with_public("Invalid token signature, consider to sign in again.")
595 .with_401()
596 })?;
597
598 let header = rmp_serde::from_slice::<LightMPAATHeader<U>>(&header).map_err(|e| {
599 ServerError::from_private(e)
600 .with_private_str("Can't deserialize LMPAAT header!")
601 .with_500()
602 })?;
603 Ok(header.common_public_fields)
604}
605
606#[cfg(all(
607 feature = "crypt-utils",
608 feature = "authnz-utils",
609 any(feature = "pqc-utils", feature = "ed25519-utils")
610))]
611pub fn lmpaat_extract_payload<T, U>(token: &str, server_keys: &SignKeypair, current_dt: chrono::DateTime<chrono::Utc>) -> MResult<T>
615where
616 T: serde::de::DeserializeOwned,
617 U: serde::de::DeserializeOwned,
618{
619 use base64::{
620 Engine as _,
621 engine::general_purpose::{STANDARD, URL_SAFE},
622 };
623 use impulse_server_kit::tracing;
624
625 let parts = token.split('.').collect::<Vec<_>>();
626
627 let sig = parts.get(1).ok_or(ServerError::from_public("Invalid token!").with_401())?;
628 let sig = STANDARD.decode(sig).map_err(|e| {
629 ServerError::from_private(e)
630 .with_private_str("Can't decode LMPAAT signature!")
631 .with_500()
632 })?;
633 let sig = rmp_serde::from_slice::<LightMPAATSignature>(&sig).map_err(|e| {
634 ServerError::from_private(e)
635 .with_private_str("Can't deserialize LMPAAT signature!")
636 .with_500()
637 })?;
638
639 tracing::debug!("LMPAAT: Got signature: {:?}", sig.sig);
640
641 let payload = parts.first().ok_or(ServerError::from_public("Invalid token!").with_401())?;
642 let payload = URL_SAFE.decode(payload).map_err(|e| {
643 ServerError::from_private(e)
644 .with_private_str("Can't decode LMPAAT payload!")
645 .with_500()
646 })?;
647
648 let header = parts.get(2).ok_or(ServerError::from_public("Invalid token!").with_401())?;
649 let header = STANDARD.decode(header).map_err(|e| {
650 ServerError::from_private(e)
651 .with_private_str("Can't decode LMPAAT header!")
652 .with_500()
653 })?;
654
655 SignKeypair::verify_token(&header, &payload, &sig.sig, &server_keys.public()).map_err(|e| {
656 ServerError::from_private(e)
657 .with_private_str("LMPAAT token is unverified!")
658 .with_public("Invalid token signature, consider to sign in again.")
659 .with_401()
660 })?;
661
662 let payload = rmp_serde::from_slice::<LightMPAATPayload<T>>(&payload).map_err(|e| {
663 ServerError::from_private(e)
664 .with_private_str("Can't deserialize LMPAAT header!")
665 .with_500()
666 })?;
667
668 tracing::debug!("LMPAAT: Expires at: {:?}", payload.exp);
669
670 if current_dt >= payload.exp {
671 return Err(
672 ServerError::from_private_str("LMPAAT token is expired!")
673 .with_public("Invalid token, consider to sign in again.")
674 .with_401(),
675 );
676 }
677
678 Ok(payload.container)
679}
680
681pub fn split_token(token: &str, max_len: usize) -> Vec<String> {
683 let mut result = Vec::new();
684 let bytes = token.as_bytes();
685 let mut start = 0;
686
687 while start < bytes.len() {
688 let end = std::cmp::min(start + max_len, bytes.len());
689 result.push(token[start..end].to_string());
690 start = end;
691 }
692
693 result
694}
695
696pub fn unite_token(parts: Vec<String>) -> String {
698 parts.join("")
699}
700
701pub fn take_exp_from_duration(duration: chrono::TimeDelta) -> chrono::DateTime<chrono::Utc> {
703 chrono::Utc::now() + duration
704}
705
706#[cfg(test)]
707mod tests {
708 use std::collections::HashSet;
709
710 use crate::{
711 AppAuthConfiguration, CipherKey, MPAATHeader, MPAATPayload, SignKeypair, TokenBundle, deploy_mpaat, mpaat_extract_common_fields,
712 mpaat_extract_payload,
713 };
714 use chrono::Utc;
715 use serde::{Deserialize, Serialize};
716
717 #[test]
718 fn verify_restore() {
719 let keypair = SignKeypair::new_ed25519().unwrap();
720 let cert = keypair.pack_keypair();
721 assert!(SignKeypair::unpack_keypair(cert).is_ok());
722 }
723
724 #[test]
725 fn verify_sign() {
726 let keypair = SignKeypair::new_ed25519().unwrap();
727 let sig = keypair.sign_raw(b"123456");
728 assert!(SignKeypair::verify_raw(b"123456", &sig, &keypair.public()).is_ok());
729 }
730
731 #[test]
732 fn verify_sign_eq() {
733 let keypair = SignKeypair::new_ed25519().unwrap();
734
735 let val = AppAuthConfiguration {
736 app_name: "default".into(),
737 allowed_tags: vec![("user", "default").into(), ("user", "main").into()],
738 sign_up_opts: crate::SignUpOpts {
739 identify_by: crate::IdenticationRequirement::Nickname {
740 spaces: false,
741 upper_registry: true,
742 characters: false,
743 },
744 allow_sign_up: true,
745 auto_assign_tags: vec![("user", "default").into(), ("user", "main").into()],
746 allowed_authn: vec![],
747 required_authn: vec![],
748 },
749 sign_in_opts: crate::SignInOpts {
750 enable_fail_to_ban: None,
751 token_encryption_type: crate::TokenEncryptionType::ChaCha20Poly1305,
752 },
753 client_based_auth_opts: crate::ClientBasedAuthorizationOpts { enable_cba: true },
754 tokens_lifetime: crate::TokenLifetimes::default(),
755 app_pkey: None,
756 };
757
758 for _ in 0..1000 {
759 let sign1 = keypair.sign(&val).unwrap();
760 let sign2 = keypair.sign(&val).unwrap();
761
762 assert_eq!(sign1.as_slice(), sign2.as_slice());
763 }
764 }
765
766 #[test]
767 fn verify_token_signs2() {
768 let keypair = SignKeypair::new_ed25519().unwrap();
769 let dt = Utc::now().checked_add_months(chrono::Months::new(1)).unwrap();
770
771 println!("Public key: {:?}", keypair.public());
772 println!("Secret key: {:?}", unsafe { keypair.private() });
773 println!();
774
775 #[derive(Deserialize, Serialize)]
776 struct Payload {
777 data: Vec<usize>,
778 }
779
780 let act = deploy_mpaat(
781 Payload { data: vec![123] },
782 Some(Payload { data: vec![456] }),
783 dt.clone(),
784 &[0, 1, 2],
785 None,
786 &keypair,
787 )
788 .unwrap();
789 println!("{}", act);
790 let cf = mpaat_extract_common_fields::<Payload>(&act, &keypair);
791 cf.unwrap();
792 let pld = mpaat_extract_payload::<Payload, Payload>(&act, None, &keypair, Utc::now());
793 pld.unwrap();
794 }
795
796 #[test]
797 fn triple_pack_unpack() {
798 let triple = TokenBundle::new_with_cba("123", "456", "789");
799 assert_eq!(TokenBundle::unpack(&triple.pack()), Some(triple));
800
801 let triple = TokenBundle::new_basic("123", "456");
802 assert_eq!(TokenBundle::unpack(&triple.pack()), Some(triple));
803 }
804}