use std::net::IpAddr; use crate::data::provider::{Provider, ProviderID}; use actix::{Actor, Context, Handler, Message, MessageResult}; use crate::data::user::{FactorID, GeneralSettings, GrantedClients, TwoFactor, User, UserID}; use crate::utils::err::Res; /// User storage interface pub trait UsersSyncBackend { fn find_by_username_or_email(&self, u: &str) -> Res>; fn find_by_email(&self, u: &str) -> Res>; fn find_by_user_id(&self, id: &UserID) -> Res>; fn get_entire_users_list(&self) -> Res>; fn create_user_account(&mut self, settings: GeneralSettings) -> Res; fn set_general_user_settings(&mut self, settings: GeneralSettings) -> Res; fn change_user_password(&mut self, id: &UserID, password: &str, temporary: bool) -> Res; fn verify_user_password(&self, user: &UserID, password: &str) -> Res; fn add_2fa_factor(&mut self, user: &UserID, factor: TwoFactor) -> Res; fn remove_2fa_factor(&mut self, user: &UserID, factor: FactorID) -> Res; fn save_new_successful_2fa_authentication(&mut self, id: &UserID, ip: IpAddr) -> Res; fn clear_2fa_login_history(&mut self, id: &UserID) -> Res; fn delete_account(&mut self, id: &UserID) -> Res; fn set_authorized_authentication_sources( &mut self, id: &UserID, sources: AuthorizedAuthenticationSources, ) -> Res; fn set_granted_2fa_clients(&mut self, id: &UserID, clients: GrantedClients) -> Res; } #[derive(Debug)] pub enum LoginResult { Error, AccountNotFound, InvalidPassword, AccountDisabled, LocalAuthForbidden, AuthFromProviderForbidden, Success(Box), } #[derive(Message)] #[rtype(LoginResult)] pub struct LocalLoginRequest { pub login: String, pub password: String, } #[derive(Message)] #[rtype(LoginResult)] pub struct ProviderLoginRequest { pub email: String, pub provider: Provider, } #[derive(Message)] #[rtype(GetUserResult)] pub struct GetUserRequest(pub UserID); #[derive(Debug)] pub struct GetUserResult(pub Option); #[derive(Message)] #[rtype(result = "bool")] pub struct VerifyUserPasswordRequest(pub UserID, pub String); #[derive(Message)] #[rtype(FindUserByUsernameResult)] pub struct FindUserByUsername(pub String); #[derive(Debug)] pub struct FindUserByUsernameResult(pub Option); #[derive(Message)] #[rtype(result = "Vec")] pub struct GetAllUsers; #[derive(Message)] #[rtype(result = "Option")] pub struct CreateAccount(pub GeneralSettings); #[derive(Message)] #[rtype(result = "bool")] pub struct ChangePasswordRequest { pub user_id: UserID, pub new_password: String, pub temporary: bool, } #[derive(Message)] #[rtype(result = "bool")] pub struct Add2FAFactor(pub UserID, pub TwoFactor); #[derive(Message)] #[rtype(result = "bool")] pub struct Remove2FAFactor(pub UserID, pub FactorID); #[derive(Message)] #[rtype(result = "bool")] pub struct AddSuccessful2FALogin(pub UserID, pub IpAddr); #[derive(Message)] #[rtype(result = "bool")] pub struct Clear2FALoginHistory(pub UserID); #[derive(Eq, PartialEq, Debug, Clone)] pub struct AuthorizedAuthenticationSources { pub local: bool, pub upstream: Vec, } #[derive(Message)] #[rtype(result = "bool")] pub struct SetAuthorizedAuthenticationSources(pub UserID, pub AuthorizedAuthenticationSources); #[derive(Message)] #[rtype(result = "bool")] pub struct SetGrantedClients(pub UserID, pub GrantedClients); #[derive(Message)] #[rtype(result = "bool")] pub struct UpdateUserSettings(pub GeneralSettings); #[derive(Message)] #[rtype(result = "bool")] pub struct DeleteUserRequest(pub UserID); pub struct UsersActor { manager: Box, } impl UsersActor { pub fn new(manager: E) -> Self where E: UsersSyncBackend + 'static, { Self { manager: Box::new(manager), } } } impl Actor for UsersActor { type Context = Context; } impl Handler for UsersActor { type Result = MessageResult; fn handle(&mut self, msg: LocalLoginRequest, _ctx: &mut Self::Context) -> Self::Result { match self.manager.find_by_username_or_email(&msg.login) { Err(e) => { log::error!("Failed to find user! {}", e); MessageResult(LoginResult::Error) } Ok(None) => MessageResult(LoginResult::AccountNotFound), Ok(Some(user)) => { if !self .manager .verify_user_password(&user.uid, &msg.password) .unwrap_or(false) { return MessageResult(LoginResult::InvalidPassword); } if !user.enabled { return MessageResult(LoginResult::AccountDisabled); } if !user.allow_local_login { return MessageResult(LoginResult::LocalAuthForbidden); } MessageResult(LoginResult::Success(Box::new(user))) } } } } impl Handler for UsersActor { type Result = MessageResult; fn handle(&mut self, msg: ProviderLoginRequest, _ctx: &mut Self::Context) -> Self::Result { match self.manager.find_by_email(&msg.email) { Err(e) => { log::error!("Failed to find user! {}", e); MessageResult(LoginResult::Error) } Ok(None) => MessageResult(LoginResult::AccountNotFound), Ok(Some(user)) => { if !user.can_login_from_provider(&msg.provider) { return MessageResult(LoginResult::AuthFromProviderForbidden); } if !user.enabled { return MessageResult(LoginResult::AccountDisabled); } MessageResult(LoginResult::Success(Box::new(user))) } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: CreateAccount, _ctx: &mut Self::Context) -> Self::Result { match self.manager.create_user_account(msg.0) { Ok(id) => Some(id), Err(e) => { log::error!("Failed to create user account! {}", e); None } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: ChangePasswordRequest, _ctx: &mut Self::Context) -> Self::Result { match self .manager .change_user_password(&msg.user_id, &msg.new_password, msg.temporary) { Ok(_) => true, Err(e) => { log::error!("Failed to change user password! {:?}", e); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: Add2FAFactor, _ctx: &mut Self::Context) -> Self::Result { match self.manager.add_2fa_factor(&msg.0, msg.1) { Ok(_) => true, Err(e) => { log::error!("Failed to add 2FA factor! {}", e); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: Remove2FAFactor, _ctx: &mut Self::Context) -> Self::Result { match self.manager.remove_2fa_factor(&msg.0, msg.1) { Ok(_) => true, Err(e) => { log::error!("Failed to remove 2FA factor! {}", e); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: AddSuccessful2FALogin, _ctx: &mut Self::Context) -> Self::Result { match self .manager .save_new_successful_2fa_authentication(&msg.0, msg.1) { Ok(_) => true, Err(e) => { log::error!("Failed to save successful 2FA authentication! {}", e); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: Clear2FALoginHistory, _ctx: &mut Self::Context) -> Self::Result { match self.manager.clear_2fa_login_history(&msg.0) { Ok(_) => true, Err(e) => { log::error!( "Failed to clear 2FA login history of user {:?} ! {}", msg.0, e ); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle( &mut self, msg: SetAuthorizedAuthenticationSources, _ctx: &mut Self::Context, ) -> Self::Result { match self .manager .set_authorized_authentication_sources(&msg.0, msg.1) { Ok(_) => true, Err(e) => { log::error!( "Failed to set authorized authentication sources for user! {}", e ); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: SetGrantedClients, _ctx: &mut Self::Context) -> Self::Result { match self.manager.set_granted_2fa_clients(&msg.0, msg.1) { Ok(_) => true, Err(e) => { log::error!("Failed to set granted 2FA clients! {}", e); false } } } } impl Handler for UsersActor { type Result = MessageResult; fn handle(&mut self, msg: GetUserRequest, _ctx: &mut Self::Context) -> Self::Result { MessageResult(GetUserResult(match self.manager.find_by_user_id(&msg.0) { Ok(r) => r, Err(e) => { log::error!("Failed to find user by id! {}", e); None } })) } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: VerifyUserPasswordRequest, _ctx: &mut Self::Context) -> Self::Result { self.manager .verify_user_password(&msg.0, &msg.1) .unwrap_or_else(|e| { log::error!("Failed to verify user password! {}", e); false }) } } impl Handler for UsersActor { type Result = MessageResult; fn handle(&mut self, msg: FindUserByUsername, _ctx: &mut Self::Context) -> Self::Result { MessageResult(FindUserByUsernameResult( self.manager .find_by_username_or_email(&msg.0) .unwrap_or_else(|e| { log::error!("Failed to find user by username or email! {}", e); None }), )) } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, _msg: GetAllUsers, _ctx: &mut Self::Context) -> Self::Result { match self.manager.get_entire_users_list() { Ok(r) => r, Err(e) => { log::error!("Failed to get entire users list! {}", e); vec![] } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: UpdateUserSettings, _ctx: &mut Self::Context) -> Self::Result { match self.manager.set_general_user_settings(msg.0) { Ok(_) => true, Err(e) => { log::error!("Failed to update general user information! {:?}", e); false } } } } impl Handler for UsersActor { type Result = ::Result; fn handle(&mut self, msg: DeleteUserRequest, _ctx: &mut Self::Context) -> Self::Result { match self.manager.delete_account(&msg.0) { Ok(_) => true, Err(e) => { log::error!("Failed to delete user account! {}", e); false } } } }