rustfmt
[recipes.git] / backend / src / hash.rs
1 use std::string::String;
2
3 use argon2::{
4 password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
5 Argon2,
6 };
7
8 pub fn hash(password: &str) -> Result<String, Box<dyn std::error::Error>> {
9 let salt = SaltString::generate(&mut OsRng);
10 let argon2 = Argon2::default();
11 argon2
12 .hash_password(password.as_bytes(), &salt)
13 .map(|h| h.to_string())
14 .map_err(|e| e.into())
15 }
16
17 pub fn verify_password(
18 password: &str,
19 hashed_password: &str,
20 ) -> Result<bool, Box<dyn std::error::Error>> {
21 let argon2 = Argon2::default();
22 let parsed_hash = PasswordHash::new(hashed_password)?;
23 Ok(argon2
24 .verify_password(password.as_bytes(), &parsed_hash)
25 .is_ok())
26 }
27
28 #[cfg(test)]
29 mod test {
30 use super::*;
31
32 #[test]
33 fn simple_case() -> Result<(), Box<dyn std::error::Error>> {
34 let password = "12345";
35 let hash = hash(password)?;
36 println!("hash: {}", &hash);
37 assert!(verify_password(password, &hash)?);
38 assert!(!verify_password("54321", &hash)?);
39 Ok(())
40 }
41
42 #[test]
43 fn password_with_special_characters() -> Result<(), Box<dyn std::error::Error>> {
44 let password = "éà ä_\\😺🎮🇨🇭";
45 let hash = hash(password)?;
46 println!("hash: {}", &hash);
47 assert!(verify_password(password, &hash)?);
48 Ok(())
49 }
50 }