1use actix_web::{Error as ActixError, HttpRequest};
4use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation};
5use serde::{Deserialize, Serialize};
6use std::env;
7
8#[derive(Serialize, Deserialize)]
10pub struct Claims {
11 pub sub: String,
12 pub exp: usize,
13}
14
15pub fn generate_token(username: &str) -> String {
17 let secret = env::var("JWT_SECRET").unwrap_or_else(|_| "bssoss-secret".to_string());
18 let expiration = chrono::Utc::now()
19 .checked_add_signed(chrono::Duration::hours(8))
20 .expect("valid timestamp")
21 .timestamp() as usize;
22
23 let claims = Claims {
24 sub: username.to_owned(),
25 exp: expiration,
26 };
27
28 encode(
29 &Header::default(),
30 &claims,
31 &EncodingKey::from_secret(secret.as_ref()),
32 )
33 .expect("Token creation failed")
34}
35
36pub fn validate_token(req: &HttpRequest) -> Result<String, ActixError> {
38 let secret = env::var("JWT_SECRET").unwrap_or_else(|_| "bssoss-secret".to_string());
39
40 if let Some(header_value) = req.headers().get("Authorization") {
41 let token = header_value
42 .to_str()
43 .map_err(|_| actix_web::error::ErrorBadRequest("Invalid authorization header"))?
44 .replace("Bearer ", "");
45
46 let token_data = decode::<Claims>(
47 &token,
48 &DecodingKey::from_secret(secret.as_ref()),
49 &Validation::default(),
50 )
51 .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid or expired token"))?;
52
53 Ok(token_data.claims.sub)
54 } else {
55 Err(actix_web::error::ErrorUnauthorized(
56 "Missing authorization header",
57 ))
58 }
59}