pub trait PasswordHasher: Send + Sync {
fn hash(&self, password: &str) -> Result<String, reinhardt_core::exception::Error>;
fn verify(&self, password: &str, hash: &str) -> Result<bool, reinhardt_core::exception::Error>;
}
#[cfg(feature = "argon2-hasher")]
#[derive(Clone)]
pub struct Argon2Hasher;
#[cfg(feature = "argon2-hasher")]
impl Argon2Hasher {
pub fn new() -> Self {
Self
}
}
#[cfg(feature = "argon2-hasher")]
impl Default for Argon2Hasher {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "argon2-hasher")]
impl PasswordHasher for Argon2Hasher {
fn hash(&self, password: &str) -> Result<String, reinhardt_core::exception::Error> {
use argon2::Argon2;
use password_hash::{PasswordHasher as _, SaltString, rand_core::OsRng};
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
argon2
.hash_password(password.as_bytes(), &salt)
.map(|hash| hash.to_string())
.map_err(|e| reinhardt_core::exception::Error::Authentication(e.to_string()))
}
fn verify(&self, password: &str, hash: &str) -> Result<bool, reinhardt_core::exception::Error> {
use argon2::Argon2;
use password_hash::{PasswordHash, PasswordVerifier};
let parsed_hash = PasswordHash::new(hash)
.map_err(|e| reinhardt_core::exception::Error::Authentication(e.to_string()))?;
Ok(Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok())
}
}