use std::future::{Ready, ready}; use actix_web::{FromRequest, http, HttpRequest, dev::Payload, web::Data}; use chrono::Utc; use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation}; use serde::{Serialize, Deserialize}; use uuid::Uuid; use gamenight_database::{user::{get_user, User}, DbPool}; use super::error::ApiError; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { exp: i64, uid: Uuid } pub struct AuthUser(pub User); // pub struct AuthUser { // pub id: Uuid, // pub username: String, // pub email: String, // pub role: Role, // } impl From for AuthUser { fn from(value: User) -> Self { Self(value) } } fn get_claims(req: &HttpRequest) -> Result { let token = req.headers() .get(http::header::AUTHORIZATION) .map(|h| h.to_str().unwrap().split_at(7).1.to_string()); let token = token.ok_or(ApiError{ status: 400, message: "JWT-token was not specified in the Authorization header as Bearer: token".to_string() })?; let secret = "secret"; Ok(decode::(token.as_str(), &DecodingKey::from_secret(secret.as_bytes()), &Validation::default())?.claims) } pub fn get_token(user: &User) -> Result { let claims = Claims { exp: Utc::now().timestamp() + chrono::Duration::days(7).num_seconds(), uid: user.id, }; let secret = "secret"; Ok(encode( &Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))?) } impl FromRequest for AuthUser { type Error = ApiError; type Future = Ready>; fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { ready( (|| -> Result{ let pool = req.app_data::>().expect("No database configured"); let mut conn = pool.get().expect("couldn't get db connection from pool"); let uid = get_claims(req)?.uid; let user = get_user(&mut conn, uid)?; Ok(user.into()) })() ) } }