use crate::{Decimal, Error, Ident, ParamsString, PasswordHash, Result, Salt};
use core::{
convert::{TryFrom, TryInto},
fmt::Debug,
};
pub trait PasswordHasher {
type Params: Clone
+ Debug
+ Default
+ for<'a> TryFrom<&'a PasswordHash<'a>, Error = Error>
+ TryInto<ParamsString, Error = Error>;
fn hash_password_customized<'a>(
&self,
password: &[u8],
algorithm: Option<Ident<'a>>,
version: Option<Decimal>,
params: Self::Params,
salt: impl Into<Salt<'a>>,
) -> Result<PasswordHash<'a>>;
fn hash_password<'a, S>(&self, password: &[u8], salt: &'a S) -> Result<PasswordHash<'a>>
where
S: AsRef<str> + ?Sized,
{
self.hash_password_customized(
password,
None,
None,
Self::Params::default(),
Salt::try_from(salt.as_ref())?,
)
}
}
pub trait PasswordVerifier {
fn verify_password(&self, password: &[u8], hash: &PasswordHash<'_>) -> Result<()>;
}
impl<T: PasswordHasher> PasswordVerifier for T {
fn verify_password(&self, password: &[u8], hash: &PasswordHash<'_>) -> Result<()> {
if let (Some(salt), Some(expected_output)) = (&hash.salt, &hash.hash) {
let computed_hash = self.hash_password_customized(
password,
Some(hash.algorithm),
hash.version,
T::Params::try_from(&hash)?,
*salt,
)?;
if let Some(computed_output) = &computed_hash.hash {
if expected_output == computed_output {
return Ok(());
}
}
}
Err(Error::Password)
}
}
pub trait McfHasher {
fn upgrade_mcf_hash<'a>(&self, hash: &'a str) -> Result<PasswordHash<'a>>;
fn verify_mcf_hash(&self, password: &[u8], mcf_hash: &str) -> Result<()>
where
Self: PasswordVerifier,
{
self.verify_password(password, &self.upgrade_mcf_hash(mcf_hash)?)
}
}