diff --git a/src/main.rs b/src/main.rs index 85719dd..a742d1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -156,6 +156,77 @@ pub mod init { } } +mod auth { + use std::collections::BTreeMap; + + use serde::{Deserialize, Serialize}; + + use axum::{ + http::{Request, StatusCode}, + middleware::Next, + response::{IntoResponse, Response}, + Json, + }; + use jwt::{Algorithm, VerifyWithKey}; + + #[derive(Clone, Debug, Serialize, Deserialize)] + pub struct UserClaims { + pub sub: String, // Subject (user ID) + pub exp: usize, // Expiration time + // Add any additional claims you need + } + + + pub async fn auth_middleware( + req: axum::http::Request, + next: axum::middleware::Next, + ) -> Result { + // Extract token from header + let token = extract_token_from_header(req.headers()) + .ok_or_else(|| (StatusCode::UNAUTHORIZED, "Missing token").into_response())?; + + // Create HMAC key from your secret + let key = jwt::Hmac::new("your-secret-key".as_bytes()) + .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Key error").into_response())?; + + // Verify and decode token + let claims: BTreeMap = token + .verify_with_key(&key) + .map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid token").into_response())?; + + // Convert to your claims struct + let user_claims = serde_json::from_value::(serde_json::to_value(claims).unwrap()) + .map_err(|_| (StatusCode::UNAUTHORIZED, "Invalid claims").into_response())?; + + // Check expiration + if user_claims.exp < current_timestamp() { + return Err((StatusCode::UNAUTHORIZED, "Token expired").into_response()); + } + + // Attach claims to request + req.extensions_mut().insert(user_claims); + + Ok(next.run(req).await) + } + + // Helper to extract token from Authorization header + fn extract_token_from_header(headers: &HeaderMap) -> Option { + headers + .get("Authorization") + .and_then(|value| value.to_str().ok()) + .and_then(|value| value.strip_prefix("Bearer ")) + .map(|s| s.to_string()) + } + + // Helper to get current timestamp + fn current_timestamp() -> usize { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs() as usize + } +} + // TODO: Move elsewhere fn get_full() -> String { get_address() + ":" + &get_port()