use crate::items; use crate::proto_utils::Proto; use rocket::State; use rocket::futures::lock::Mutex; use std::collections::HashMap; use uuid::Uuid; pub struct AuthState { // Map token -> username tokens: Mutex>, } impl AuthState { pub fn new() -> Self { Self { tokens: Mutex::new(HashMap::new()), } } } impl Default for AuthState { fn default() -> Self { Self::new() } } #[derive(Debug)] #[allow(dead_code)] pub struct Token { pub token: String, pub username: String, } #[rocket::async_trait] impl<'r> rocket::request::FromRequest<'r> for Token { type Error = (); async fn from_request( request: &'r rocket::Request<'_>, ) -> rocket::request::Outcome { let token = request.headers().get_one("Authorization"); match token { Some(token) => { // Check if token starts with "Bearer " if let Some(token) = token.strip_prefix("Bearer ") { let state = request.guard::<&State>().await.unwrap(); let tokens = state.tokens.lock().await; if let Some(username) = tokens.get(token) { return rocket::request::Outcome::Success(Token { token: token.to_string(), username: username.clone(), }); } } rocket::request::Outcome::Error((rocket::http::Status::Unauthorized, ())) } None => rocket::request::Outcome::Error((rocket::http::Status::Unauthorized, ())), } } } #[post("/login", data = "")] pub async fn login( state: &State, user_list: &State>>, request: Proto, ) -> items::LoginResponse { let req = request.into_inner(); let users = user_list.lock().await; if let Some(user) = users .iter() .find(|u| u.person.name.to_lowercase() == req.username.to_lowercase()) && bcrypt::verify(&req.password, &user.password_hash).unwrap_or(false) { let token = Uuid::new_v4().to_string(); let mut tokens = state.tokens.lock().await; tokens.insert(token.clone(), req.username); return items::LoginResponse { token, success: true, message: "Login successful".to_string(), }; } items::LoginResponse { token: "".to_string(), success: false, message: "Invalid credentials".to_string(), } } #[post("/logout", data = "")] pub async fn logout( state: &State, request: Proto, ) -> items::LogoutResponse { let req = request.into_inner(); let mut tokens = state.tokens.lock().await; if tokens.remove(&req.token).is_some() { items::LogoutResponse { success: true, message: "Logged out successfully".to_string(), } } else { items::LogoutResponse { success: false, message: "Invalid token".to_string(), } } } #[post("/get_auth_status", data = "")] pub async fn get_auth_status( state: &State, request: Proto, ) -> items::AuthStatusResponse { let req = request.into_inner(); let tokens = state.tokens.lock().await; if let Some(username) = tokens.get(&req.token) { items::AuthStatusResponse { authenticated: true, username: username.clone(), message: "Authenticated".to_string(), } } else { items::AuthStatusResponse { authenticated: false, username: "".to_string(), message: "Not authenticated".to_string(), } } }