use std::future::{ready, Ready}; use actix_web::{dev::Payload, http, web::Data, FromRequest, HttpRequest}; use chrono::Utc; use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; 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()) })()) } }