1use chrono::{Duration, Utc};
2use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, encode};
3use serde::{Deserialize, Serialize};
4use server_config::{jwt::JwtConfig, uri::IgnoreUri};
5
6use crate::error::auth::AuthError;
7
8#[derive(Debug, Serialize, Deserialize, Clone)]
10pub struct Claims {
11 pub sub: String, pub exp: i64, pub iat: i64, pub data: Option<String>,
15}
16
17pub struct JwtService {
19 config: JwtConfig,
20}
21
22impl JwtService {
23 pub fn new(mut config: JwtConfig) -> Self {
24 if let Some(data) = &mut config.ignore_uris {
25 JwtService::methods_to_uppercase(data);
26 }
27 print!("{:?}", &config);
28 Self { config }
29 }
30
31 pub fn generate_token(
33 &self,
34 user_info: &str,
35 data: Option<String>,
36 ) -> Result<String, jsonwebtoken::errors::Error> {
37 let now = Utc::now();
38 let exp = now + Duration::hours(self.config.expiration_hours);
39
40 let claims = Claims {
41 sub: user_info.to_string(),
42 exp: exp.timestamp(),
43 iat: now.timestamp(),
44 data,
45 };
46
47 encode(
48 &Header::default(),
49 &claims,
50 &EncodingKey::from_secret(self.config.secret.as_ref()),
51 )
52 }
53
54 pub fn verify_token(&self, token: &str) -> Result<Claims, AuthError> {
56 let token_data = decode::<Claims>(
57 token,
58 &DecodingKey::from_secret(self.config.secret.as_ref()),
59 &Validation::new(Algorithm::HS256),
60 )
61 .map_err(|_| AuthError::InvalidToken)?;
62
63 let now = Utc::now().timestamp();
65 if token_data.claims.exp < now {
66 return Err(AuthError::ExpiredToken);
67 }
68
69 Ok(token_data.claims)
70 }
71
72 pub fn get_secret(&self) -> String {
74 self.config.secret.clone()
75 }
76
77 pub fn get_expiration(&self) -> i64 {
79 self.config.expiration_hours
80 }
81
82 pub fn is_ignore_uri(&self, uri: &str, method: &str) -> bool {
84 if let Some(data) = &self.config.ignore_uris {
85 for item in data.iter() {
86 if uri.starts_with(&item.path) && item.method.contains(&method.to_uppercase()) {
88 return true;
89 }
90 }
91 false
92 } else {
93 false
94 }
95 }
96
97 pub fn methods_to_uppercase(data: &mut [IgnoreUri]) {
99 for item in data.iter_mut() {
100 for method in item.method.iter_mut() {
101 *method = method.to_uppercase();
102 }
103 }
104 }
105}