From 6fdac7fbb16447dcd3cd8bb38863232bf8411904 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Wed, 30 Mar 2022 12:41:22 +0200 Subject: [PATCH] Add communication with user actor --- src/actors/users_actor.rs | 35 +++++++++++++++++++++++++++-- src/controllers/login_controller.rs | 35 ++++++++++++++++++++++++----- src/data/entity_manager.rs | 6 +++++ src/data/user.rs | 24 +++++++++++++++++++- src/{utils.rs => utils/mod.rs} | 0 templates/login.html | 4 ++-- 6 files changed, 94 insertions(+), 10 deletions(-) rename src/{utils.rs => utils/mod.rs} (100%) diff --git a/src/actors/users_actor.rs b/src/actors/users_actor.rs index 5ac2a6e..65699b7 100644 --- a/src/actors/users_actor.rs +++ b/src/actors/users_actor.rs @@ -1,7 +1,21 @@ -use actix::{Actor, Context}; +use actix::{Actor, Context, Handler, Message, MessageResult}; use crate::data::entity_manager::EntityManager; -use crate::data::user::User; +use crate::data::user::{User, verify_password}; + +#[derive(Debug)] +pub enum LoginResult { + AccountNotFound, + InvalidPassword, + Success(User), +} + +#[derive(Message)] +#[rtype(LoginResult)] +pub struct LoginRequest { + pub login: String, + pub password: String, +} pub struct UsersActor { manager: EntityManager, @@ -15,4 +29,21 @@ impl UsersActor { impl Actor for UsersActor { type Context = Context; +} + +impl Handler for UsersActor { + type Result = MessageResult; + + fn handle(&mut self, msg: LoginRequest, _ctx: &mut Self::Context) -> Self::Result { + match self.manager.find_by_username_or_email(&msg.login) { + None => MessageResult(LoginResult::AccountNotFound), + Some(user) => { + if !verify_password(msg.password, &user.password) { + return MessageResult(LoginResult::InvalidPassword); + } + + MessageResult(LoginResult::Success(user)) + } + } + } } \ No newline at end of file diff --git a/src/controllers/login_controller.rs b/src/controllers/login_controller.rs index a96fa96..a6c2e23 100644 --- a/src/controllers/login_controller.rs +++ b/src/controllers/login_controller.rs @@ -1,6 +1,9 @@ -use actix_web::{HttpResponse, Responder}; +use actix::Addr; +use actix_web::{HttpResponse, Responder, web}; use askama::Template; +use crate::actors::users_actor::{LoginResult, UsersActor}; +use crate::actors::users_actor; use crate::constants::APP_NAME; #[derive(Template)] @@ -16,20 +19,42 @@ struct BaseLoginPage { #[template(path = "login.html")] struct LoginTemplate { _parent: BaseLoginPage, - mail: String, + login: String, } +#[derive(serde::Deserialize)] +pub struct LoginRequest { + login: String, + password: String, +} + +/// Authenticate user +pub async fn login_route(users: web::Data>, + req: Option>) -> impl Responder { + let mut danger = String::new(); + let mut login = String::new(); + + // Try to authenticate user + if let Some(req) = &req { + login = req.login.clone(); + let response: LoginResult = users.send(users_actor::LoginRequest { + login: login.clone(), + password: req.password.clone(), + }).await.unwrap(); + + danger = format!("{:?}", response) + } + -pub async fn login_route() -> impl Responder { HttpResponse::Ok() .content_type("text/html") .body(LoginTemplate { _parent: BaseLoginPage { page_title: "Login", - danger: "".to_string(), + danger, success: "".to_string(), app_name: APP_NAME, }, - mail: "".to_string() + login, }.render().unwrap()) } \ No newline at end of file diff --git a/src/data/entity_manager.rs b/src/data/entity_manager.rs index 027d5be..53d5167 100644 --- a/src/data/entity_manager.rs +++ b/src/data/entity_manager.rs @@ -1,4 +1,5 @@ use std::path::{Path, PathBuf}; +use std::slice::Iter; use crate::utils::err::Res; @@ -44,4 +45,9 @@ impl EntityManager where E: serde::Serialize + serde::de::DeserializeOwned self.list.push(el); self.save() } + + /// Iterate over the entries of this entity manager + pub fn iter(&self) -> Iter<'_, E> { + self.list.iter() + } } \ No newline at end of file diff --git a/src/data/user.rs b/src/data/user.rs index 6ba3749..162ece0 100644 --- a/src/data/user.rs +++ b/src/data/user.rs @@ -1,3 +1,4 @@ +use crate::data::entity_manager::EntityManager; use crate::data::service::ServiceID; use crate::utils::err::Res; @@ -38,11 +39,32 @@ impl Default for User { need_reset_password: false, enabled: true, admin: false, - authorized_services: None + authorized_services: None, } } } pub fn hash_password>(pwd: P) -> Res { Ok(bcrypt::hash(pwd, bcrypt::DEFAULT_COST)?) +} + +pub fn verify_password>(pwd: P, hash: &str) -> bool { + match bcrypt::verify(pwd, hash) { + Ok(r) => r, + Err(e) => { + log::warn!("Failed to verify password! {:?}", e); + false + } + } +} + +impl EntityManager { + pub fn find_by_username_or_email(&self, u: &str) -> Option { + for entry in self.iter() { + if entry.username.eq(u) || entry.email.eq(u) { + return Some(entry.clone()); + } + } + None + } } \ No newline at end of file diff --git a/src/utils.rs b/src/utils/mod.rs similarity index 100% rename from src/utils.rs rename to src/utils/mod.rs diff --git a/templates/login.html b/templates/login.html index dac46a1..370a849 100644 --- a/templates/login.html +++ b/templates/login.html @@ -3,8 +3,8 @@
- +