use argon2::{ Argon2, password_hash::{ PasswordHash, PasswordHasher as Argon2Hasher, PasswordVerifier, SaltString, rand_core::OsRng, }, }; use async_trait::async_trait; use rand::RngCore; use crate::ports::{PasswordHasher, TokenGenerator}; pub struct Argon2PasswordHasher; #[async_trait] impl PasswordHasher for Argon2PasswordHasher { fn hash(&self, password: &str) -> Result { let salt = SaltString::generate(&mut OsRng); Argon2::default() .hash_password(password.as_bytes(), &salt) .map(|hash| hash.to_string()) .map_err(|error| error.to_string()) } fn verify(&self, password: &str, encoded_hash: &str) -> Result { let hash = PasswordHash::new(encoded_hash).map_err(|error| error.to_string())?; Ok(Argon2::default() .verify_password(password.as_bytes(), &hash) .is_ok()) } } pub struct RandomTokenGenerator; #[async_trait] impl TokenGenerator for RandomTokenGenerator { fn generate(&self) -> String { new_secret() } } pub fn new_secret() -> String { let mut bytes = [0_u8; 32]; OsRng.fill_bytes(&mut bytes); hex::encode(bytes) }