use std::sync::Arc; use axum::{ Json, body::Body, extract::State, http::{Request, StatusCode, header}, middleware::Next, response::IntoResponse, }; use axum_extra::extract::CookieJar; use jsonwebtoken::DecodingKey; use serde_json::json; use crate::{ AppState, cookie::jwt::decode_token, handlers::auth::filter_user, models::{LoginScheme, User}, }; pub async fn validate_token( cookies: CookieJar, State(data): State>, mut request: Request, next: Next, ) -> Result)> { let token = cookies .get("token") .map(|cookie| cookie.value().to_string()) .or_else(|| { request .headers() .get(header::AUTHORIZATION) .and_then(|header| header.to_str().ok()) .and_then(|value| { if value.starts_with("Bearer ") { Some(value[7..].to_owned()) } else { None } }) }); let token = token.ok_or_else(|| { let error = json!({ "status": "error", "message": "Please provide a valid token" }); (StatusCode::UNAUTHORIZED, Json(error)) })?; let claims = decode_token( token, &DecodingKey::from_secret(data.env.token_secret.as_ref()), ) .map_err(|(status, json_err)| { let error = json!({ "status": json_err.status, "message": json_err.message }); (status, Json(error)) })?; let uuid = (&claims.sub).parse::().map_err(|_| { let error = json!({ "status": "error", "message": "Invalid user id" }); (StatusCode::UNAUTHORIZED, Json(error)) })?; let user = sqlx::query_as::<_, User>(r#"SELECT * FROM users WHERE id = $1"#) .bind(uuid) .fetch_optional(&data.db) .await .map_err(|e| { let error = json!({ "status": "error", "message": format!("Database error: {}", e) }); (StatusCode::INTERNAL_SERVER_ERROR, Json(error)) })?; let user = user.ok_or_else(|| { let error = json!({ "status": "error", "message": "Invalid user" }); (StatusCode::UNAUTHORIZED, Json(error)) })?; request.extensions_mut().insert(filter_user(&user)); Ok(next.run(request).await) }