use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
pub fn hash_password(password: &str) -> Result<String, String> {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
argon2
.hash_password(password.as_bytes(), &salt)
.map(|h| h.to_string())
.map_err(|e| format!("Failed to hash password: {}", e))
}
pub fn verify_password(password: &str, hash: &str) -> Result<bool, String> {
let parsed_hash =
PasswordHash::new(hash).map_err(|e| format!("Invalid password hash: {}", e))?;
Ok(Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash)
.is_ok())
}
pub fn generate_temp_password() -> String {
use rand::RngExt;
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%";
let mut rng = rand::rng();
(0..16)
.map(|_| {
let idx = rng.random_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_and_verify() {
let password = "SecurePassword123!";
let hash = hash_password(password).unwrap();
assert!(verify_password(password, &hash).unwrap());
assert!(!verify_password("wrong_password", &hash).unwrap());
}
#[test]
fn test_generate_temp_password() {
let password = generate_temp_password();
assert_eq!(password.len(), 16);
}
}