use crate::error::ApiError; use argon2::{ password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, Argon2, PasswordHash, PasswordVerifier, }; use sea_orm::{ ActiveModelTrait, ActiveValue::{NotSet, Set}, ColumnTrait, DbErr, EntityTrait, ModelTrait, QueryFilter, TransactionTrait, }; use uuid::Uuid; use crate::{entity, Database}; impl Database { pub async fn create_user( &self, name: String, username: String, password: String, ) -> Result { let argon2 = Argon2::default(); let salt = SaltString::generate(&mut OsRng); let hash = argon2 .hash_password(password.as_bytes(), &salt) .map_err(|err| ApiError::Argon2Error(err.to_string()))? .to_string(); let user = self .conn .transaction::<_, entity::user::Model, DbErr>(|txn| { Box::pin(async move { let user = entity::user::ActiveModel { id: NotSet, name: Set(name), username: Set(username), }; let user: entity::user::Model = user.insert(txn).await?; let local_auth = entity::local_auth::ActiveModel { id: Set(user.id), hash: Set(hash), password_change_required: NotSet, }; local_auth.insert(txn).await?; Ok(user) }) }) .await?; Ok(user) } pub async fn verify_local_user( &self, username: &str, password: &str, ) -> Result { let user = entity::user::Entity::find() .filter(entity::user::Column::Username.eq(username)) .one(&self.conn) .await? .ok_or(ApiError::Unauthorized)?; let local_auth = user .find_related(entity::local_auth::Entity) .one(&self.conn) .await? .ok_or(ApiError::Unauthorized)?; let argon2 = Argon2::default(); let password_hash = PasswordHash::new(&local_auth.hash) .map_err(|err| ApiError::Argon2Error(err.to_string()))?; if let Err(_) = argon2.verify_password(password.as_bytes(), &password_hash) { return Err(ApiError::Unauthorized); } Ok(user.id) } pub async fn verify_ldap_user() {} pub async fn change_user_password() {} }