1use crate::{Config, Error, Result};
2use argon2::{Argon2, Params, PasswordHasher};
3use password_hash::{Salt, SaltString};
4
5pub(crate) async fn get_hasher<'a>() -> Result<Argon2<'a>> {
6 let config = crate::config::GLOBAL_CONFIG
7 .get()
8 .ok_or(Error::MissingConfig)?
9 .read()
10 .await;
11
12 let Config {
13 algorithm,
14 version,
15 secret_key,
16 memory_cost,
17 iterations,
18 parallelism,
19 output_length,
20 } = *config;
21 let params = Params::new(memory_cost, iterations, parallelism, output_length)?;
22 Ok(match secret_key {
23 Some(key) => Argon2::new_with_secret(key, algorithm, version, params),
24 None => Ok(Argon2::new(algorithm, version, params)),
25 }?)
26}
27
28pub async fn hash_raw(password: impl AsRef<[u8]>) -> crate::Result<Vec<u8>> {
36 let hasher = get_hasher().await?;
37 let password = password.as_ref().to_owned();
38
39 let res = tokio::task::spawn_blocking(move || {
40 let salt_str = SaltString::generate(rand::thread_rng());
41 let salt = salt_str.as_salt();
42 let mut output = Vec::new();
43 hasher
44 .hash_password_into(&*password, salt.as_bytes(), &mut output)
45 .map(|_| output)
46 });
47
48 Ok(res.await??)
49}
50
51pub async fn hash(password: impl AsRef<[u8]>) -> crate::Result<String> {
59 let hasher = get_hasher().await?;
60 let password = password.as_ref().to_owned();
61
62 let res = tokio::task::spawn_blocking(move || {
63 let salt_str = SaltString::generate(rand::thread_rng());
64 let salt = Salt::from(&salt_str);
65 hasher
66 .hash_password(&*password, &salt)
67 .map(|x| x.serialize().to_string())
68 });
69
70 Ok(res.await??)
71}