use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Algorithm, Argon2, Params, Version,
};
#[tauri::command]
pub fn hash_password(
password: String,
algorithm: String,
cost: u32,
memory_kib: u32,
parallelism: u32,
) -> Result<String, String> {
match algorithm.as_str() {
"bcrypt" => bcrypt::hash(&password, cost).map_err(|e| e.to_string()),
"argon2id" => {
let params =
Params::new(memory_kib, cost, parallelism, None).map_err(|e| e.to_string())?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
let salt = SaltString::generate(&mut OsRng);
argon2
.hash_password(password.as_bytes(), &salt)
.map(|h| h.to_string())
.map_err(|e| e.to_string())
}
other => Err(format!("Unsupported algorithm: {other}")),
}
}
#[tauri::command]
pub fn verify_password(password: String, hash: String) -> Result<bool, String> {
if hash.starts_with("$2") {
bcrypt::verify(&password, &hash).map_err(|e| e.to_string())
} else if hash.starts_with("$argon2") {
let parsed = PasswordHash::new(&hash).map_err(|e| e.to_string())?;
Ok(Argon2::default()
.verify_password(password.as_bytes(), &parsed)
.is_ok())
} else {
Err("Unrecognized hash format (expected bcrypt $2*$ or Argon2 $argon2*$)".to_string())
}
}