diff --git a/crates/manager-core/src/auth_api.rs b/crates/manager-core/src/auth_api.rs index 6fd8a76..2223c58 100644 --- a/crates/manager-core/src/auth_api.rs +++ b/crates/manager-core/src/auth_api.rs @@ -73,10 +73,9 @@ pub struct AdminUserDto { async fn login(State(state): State, Json(input): Json) -> Response { // Always perform a verify, even on missing/inactive users, to flatten - // timing and prevent username enumeration. The dummy hash is a real - // Argon2id PHC string for "x" — the verify will simply fail. - const DUMMY_HASH: &str = "$argon2id$v=19$m=19456,t=2,p=1$dGltaW5nLWZsYXR0ZW4$Ux6dgPqgX1Mhg5fRgIeKZF3MWdYqJplKEz/cKLcSdks"; - + // timing and prevent username enumeration. The dummy hash is the + // shared `TIMING_FLAT_DUMMY_HASH` constant from `auth.rs` so the + // single PHC value lives in exactly one place (v1.1.9 F4 dedup). let creds = match state .users .get_credentials_by_username(&input.username) @@ -93,7 +92,11 @@ async fn login(State(state): State, Json(input): Json) // canonical row used in the response DTO. let (stored_hash, user_id, is_active) = match creds { Some(c) => (c.password_hash, Some(c.id), c.is_active), - None => (DUMMY_HASH.to_string(), None, false), + None => ( + crate::auth::TIMING_FLAT_DUMMY_HASH.to_string(), + None, + false, + ), }; let password_ok = verify_password(&stored_hash, &input.password);