diff --git a/src/core/utils/hash.rs b/src/core/utils/hash.rs index 9412228f..d6efaff9 100644 --- a/src/core/utils/hash.rs +++ b/src/core/utils/hash.rs @@ -1,4 +1,4 @@ -use std::sync::Mutex; +use std::sync::OnceLock; use argon2::{ password_hash, password_hash::SaltString, Algorithm, Argon2, Params, PasswordHash, PasswordHasher, @@ -9,10 +9,24 @@ const M_COST: u32 = Params::DEFAULT_M_COST; // memory size in 1 KiB blocks const T_COST: u32 = Params::DEFAULT_T_COST; // nr of iterations const P_COST: u32 = Params::DEFAULT_P_COST; // parallelism -static STATE: Mutex>> = Mutex::new(None); +static ARGON: OnceLock> = OnceLock::new(); -#[allow(clippy::let_underscore_must_use)] -pub fn init() { +pub fn password(password: &str) -> Result { + let salt = SaltString::generate(rand::thread_rng()); + ARGON + .get_or_init(init_argon) + .hash_password(password.as_bytes(), &salt) + .map(|it| it.to_string()) +} + +pub fn verify_password(password: &str, password_hash: &str) -> Result<(), password_hash::Error> { + let password_hash = PasswordHash::new(password_hash)?; + ARGON + .get_or_init(init_argon) + .verify_password(password.as_bytes(), &password_hash) +} + +fn init_argon() -> Argon2<'static> { // 19456 Kib blocks, iterations = 2, parallelism = 1 // * debug_assert!(M_COST == 19_456, "M_COST default changed"); @@ -23,29 +37,7 @@ pub fn init() { let version = Version::default(); let out_len: Option = None; let params = Params::new(M_COST, T_COST, P_COST, out_len).expect("valid parameters"); - let state = Argon2::new(algorithm, version, params); - _ = STATE.lock().expect("hashing state locked").insert(state); -} - -pub fn password(password: &str) -> Result { - let salt = SaltString::generate(rand::thread_rng()); - STATE - .lock() - .expect("hashing state locked") - .as_ref() - .expect("hashing state initialized") - .hash_password(password.as_bytes(), &salt) - .map(|it| it.to_string()) -} - -pub fn verify_password(password: &str, password_hash: &str) -> Result<(), password_hash::Error> { - let password_hash = PasswordHash::new(password_hash)?; - STATE - .lock() - .expect("hashing state locked") - .as_ref() - .expect("hashing state initialized") - .verify_password(password.as_bytes(), &password_hash) + Argon2::new(algorithm, version, params) } #[cfg(test)] @@ -53,7 +45,6 @@ mod tests { #[test] fn password_hash_and_verify() { use crate::utils::hash; - hash::init(); let preimage = "temp123"; let digest = hash::password(preimage).expect("digest"); hash::verify_password(preimage, &digest).expect("verified"); @@ -63,7 +54,6 @@ mod tests { #[should_panic(expected = "unverified")] fn password_hash_and_verify_fail() { use crate::utils::hash; - hash::init(); let preimage = "temp123"; let fakeimage = "temp321"; let digest = hash::password(preimage).expect("digest"); diff --git a/src/main/server.rs b/src/main/server.rs index 08d81d01..dfe75541 100644 --- a/src/main/server.rs +++ b/src/main/server.rs @@ -4,7 +4,7 @@ use conduit::{ config::Config, info, log::{self}, - utils::{hash, sys}, + utils::sys, Error, Result, }; use tokio::runtime; @@ -39,7 +39,6 @@ impl Server { #[cfg(unix)] sys::maximize_fd_limit().expect("Unable to increase maximum soft and hard file descriptor limit"); - hash::init(); info!( server_name = %config.server_name,