diff --git a/crates/adapters/auth/Cargo.toml b/crates/adapters/auth/Cargo.toml index 136ce83..58f56d0 100644 --- a/crates/adapters/auth/Cargo.toml +++ b/crates/adapters/auth/Cargo.toml @@ -13,4 +13,5 @@ tokio = { workspace = true } serde = { workspace = true } jsonwebtoken = "9" argon2 = "0.5" +bcrypt = "0.15" rand = "0.8" diff --git a/crates/adapters/auth/src/lib.rs b/crates/adapters/auth/src/lib.rs index 2a9a0c3..35a0270 100644 --- a/crates/adapters/auth/src/lib.rs +++ b/crates/adapters/auth/src/lib.rs @@ -76,6 +76,10 @@ impl PasswordHasher for Argon2PasswordHasher { } async fn verify(&self, plain: &str, hash: &PasswordHash) -> Result { + if hash.0.starts_with("$2") { + return bcrypt::verify(plain, &hash.0) + .map_err(|e| DomainError::Internal(e.to_string())); + } use argon2::{password_hash::PasswordHash as ArgonHash, Argon2, PasswordVerifier}; let parsed = ArgonHash::new(&hash.0).map_err(|e| DomainError::Internal(e.to_string()))?; Ok(Argon2::default() diff --git a/crates/domain/src/value_objects.rs b/crates/domain/src/value_objects.rs index 6998aa5..c35651c 100644 --- a/crates/domain/src/value_objects.rs +++ b/crates/domain/src/value_objects.rs @@ -44,9 +44,12 @@ impl Username { if s.is_empty() || s.len() > 32 { return Err(DomainError::InvalidInput("username: 1-32 chars".into())); } - if !s.chars().all(|c| c.is_alphanumeric() || c == '_') { + if !s + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '.') + { return Err(DomainError::InvalidInput( - "username: alphanumeric or underscore only".into(), + "username: alphanumeric, underscore, or dot only".into(), )); } Ok(Self(s))