use actix_identity::Identity; use actix_session::Session; use actix_web::{ delete, http::{header::ContentType, Method}, post, web, HttpMessage, HttpRequest, HttpResponse, Responder, }; use serde::{Deserialize, Serialize}; use crate::{model::user::User, repo::user_repository::UserRepository}; pub mod todo_routes; pub mod user_routes; #[derive(Debug, Deserialize)] pub struct LoginData { login: String, password: String, } #[derive(Debug, Serialize)] pub struct ActiveUser { id: uuid::Uuid, login: String, } /// Helper function to get a valid User from session. fn get_user_from_session(session: Session) -> Option { match session.get::("user") { Ok(Some(user)) => Some(user), Ok(None) => { log::warn!("Could no DESERIALIZE user from session despite someone is logged in"); None } Err(err) => { log::warn!("Could no GET user from session despite someone is logged in: {err}"); None } } } /// Handles any route that is not defined explicitly. pub async fn index(id: Option, method: Method) -> impl Responder { match method { Method::GET => match id { Some(id) => HttpResponse::Ok() .content_type(ContentType::plaintext()) .body(format!( "You are logged in. Welcome! ({:?})", id.id().unwrap() )), None => HttpResponse::Unauthorized().body("Please log in to continue!"), }, _ => HttpResponse::Forbidden().finish(), } } /// Creates an Identity in the session if the provided credentials are valid. #[post("/login")] pub async fn post_login( req: HttpRequest, payload: web::Json, repo: web::Data, session: Session, ) -> impl Responder { log::debug!("Received {payload:?}"); match repo.read_by_login(&payload.login) { Ok(Some(user)) => { let hash = sha256::digest(String::from(format!("{}{}", payload.password, user.salt()))); if hash == user.hash() { log::debug!("User successfully logged in: {payload:?} == {user:?}"); // TODO: Mayb handle more gracefully Identity::login(&req.extensions(), format!("{}", user.id())) .expect("Log the user in"); // Create answer for frontend let res = ActiveUser { id: user.id().clone(), login: String::from(user.login()), }; // let res = format!( // "{{'id': '{}', 'login': '{}'}}", // user.id(), // user.login() // ); // TODO: Mayb handle more gracefully session .insert("user", user) .expect("Insert user into session"); HttpResponse::Ok().json(res) } else { log::debug!( "Wrong password hash for user: ({}: {}) != ({}: {})", payload.login, hash, user.login(), user.hash() ); HttpResponse::Unauthorized().finish() } } Ok(None) => { log::debug!("User not found: {payload:?}"); HttpResponse::Unauthorized().finish() } Err(_) => { let msg = format!("Could not create user: {payload:?}"); log::debug!("{}", msg); HttpResponse::InternalServerError().body(msg) } } } /// Removes the current Identity from the session -> logs the user out. #[delete("/logout")] pub async fn delete_logout(id: Identity) -> impl Responder { id.logout(); HttpResponse::Ok() }