use argon2::{
Argon2, PasswordHash, PasswordVerifier,
password_hash::{PasswordHasher, SaltString, rand_core::OsRng},
};
use serde::{Deserialize, Serialize};
use crate::accounts::PasswordCreationError;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct Password(String);
impl Password {
pub fn new(password: String) -> Result<Self, PasswordCreationError> {
let len = password.chars().count();
if !(15..=128).contains(&len) {
return Err(PasswordCreationError::InvalidLength(len as u32));
}
let salt = SaltString::generate(&mut OsRng);
let password = Argon2::default()
.hash_password(password.as_bytes(), &salt)
.expect("Failure requires extreme conditions");
Ok(Password(password.to_string()))
}
pub fn verify(&self, password: impl AsRef<str>) -> bool {
let password: String = password.as_ref().chars().take(128).collect();
let password_hash = PasswordHash::new(&self.0).expect("Passwords are PHC compliant");
match Argon2::default().verify_password(password.as_bytes(), &password_hash) {
Ok(()) => true,
Err(argon2::password_hash::Error::Password) => false,
Err(err) => panic!("Inputs should never cause a panic: {err}"),
}
}
}