1mod models;
2
3use base64::Engine as _;
4use serde::Deserialize;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7pub use models::{Account, Device, Organization};
8
9const EXPIRATION_MARGIN: u64 = 60 * 5;
10
11#[derive(Debug, Deserialize)]
14pub struct Token {
15 pub account: Account,
16 pub iat: u64,
17 pub exp: u64,
18 #[serde(skip)]
19 pub jwt: String,
20}
21
22impl Token {
23 #[allow(clippy::missing_errors_doc)]
32 pub fn from_jwt(jwt: &str) -> Result<Self, String> {
33 let parts: Vec<&str> = jwt.split('.').collect();
34
35 if parts.len() != 3 {
36 return Err(String::from("Malformed JWT"));
37 }
38
39 let decoded_payload = base64::engine::general_purpose::URL_SAFE_NO_PAD
40 .decode(parts[1])
41 .map_err(|e| e.to_string())?;
42
43 let mut token: Token =
44 serde_json::from_slice(&decoded_payload).map_err(|e| e.to_string())?;
45 token.jwt = jwt.to_string();
46
47 Ok(token)
48 }
49
50 #[must_use]
52 pub fn is_expired(&self) -> bool {
53 let Ok(duration) = SystemTime::now().duration_since(UNIX_EPOCH) else {
55 return true;
56 };
57 self.exp <= (duration.as_secs() - EXPIRATION_MARGIN)
58 }
59}