use crate::{Config, Error, Result};
use argon2::{Argon2, Params, PasswordHasher};
use password_hash::{Salt, SaltString};
pub(crate) async fn get_hasher<'a>() -> Result<Argon2<'a>> {
let config = crate::config::GLOBAL_CONFIG
.get()
.ok_or(Error::MissingConfig)?
.read()
.await;
let Config {
algorithm,
version,
secret_key,
memory_cost,
iterations,
parallelism,
output_length,
} = *config;
let params = Params::new(memory_cost, iterations, parallelism, output_length)?;
Ok(match secret_key {
Some(key) => Argon2::new_with_secret(key, algorithm, version, params),
None => Ok(Argon2::new(algorithm, version, params)),
}?)
}
pub async fn hash_raw(password: impl AsRef<[u8]>) -> crate::Result<Vec<u8>> {
let hasher = get_hasher().await?;
let password = password.as_ref().to_owned();
let res = tokio::task::spawn_blocking(move || {
let salt_str = SaltString::generate(rand::thread_rng());
let salt = salt_str.as_salt();
let mut output = Vec::new();
hasher
.hash_password_into(&*password, salt.as_bytes(), &mut output)
.map(|_| output)
});
Ok(res.await??)
}
pub async fn hash(password: impl AsRef<[u8]>) -> crate::Result<String> {
let hasher = get_hasher().await?;
let password = password.as_ref().to_owned();
let res = tokio::task::spawn_blocking(move || {
let salt_str = SaltString::generate(rand::thread_rng());
let salt = Salt::from(&salt_str);
hasher
.hash_password(&*password, &salt)
.map(|x| x.serialize().to_string())
});
Ok(res.await??)
}