use argon2::Argon2; use password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString}; use rand_core::OsRng; #[derive(Debug, sqlx::Type)] #[sqlx(transparent)] pub struct StoredHash(String); impl StoredHash { pub fn new(password: &str) -> Result { let salt = SaltString::generate(&mut OsRng); let argon2 = Argon2::default(); let hash = argon2 .hash_password(password.as_bytes(), &salt)? .to_string(); Ok(Self(hash)) } pub fn verify(&self, password: &str) -> Result { let hash = PasswordHash::new(&self.0)?; match Argon2::default().verify_password(password.as_bytes(), &hash) { // Successful authentication, not an error Ok(()) => Ok(true), // Unsuccessful authentication, also not an error Err(password_hash::errors::Error::Password) => Ok(false), // Password validation failed for some other reason, treat as an error Err(err) => Err(err), } } }