Compare commits

...
Author SHA1 Message Date
Brandon Thomas 6e8875b07c fix password issue 2026-03-31 14:54:09 -04:00
Brandon Thomas e391bbff04 this is paging me 2026-03-31 14:37:41 -04:00
@@ -6,7 +6,9 @@ pub fn bcrypt_confirm_password(password: String, bcrypt_hash: &str) -> Result<bo
return Err(PasswordConfirmError::HashNotProvided);
}
if bcrypt_hash == PASSWORD_HASH_SENTINEL_VALUE {
// The database stores the sentinel "*" in a BINARY(60) column, which pads with null bytes.
// This reproduces the real-world value: "*" followed by 59 null bytes.
if bcrypt_hash.trim_end_matches('\0') == PASSWORD_HASH_SENTINEL_VALUE {
return Err(PasswordConfirmError::HashIsSentinelValue);
}
@@ -20,7 +22,7 @@ mod tests {
use crate::errors::password_confirm_error::PasswordConfirmError;
#[test]
fn test_confirmation() {
fn test_several_password_hash_pairs() {
// NB: This is to make sure we don't migrate the algorithm to a state where it won't work anymore.
// NB: Be mindful that these are expensive to compute and don't add too many test cases.
let hash_to_passwords = [
@@ -47,4 +49,18 @@ mod tests {
let result = bcrypt_confirm_password("password".to_string(), "*");
assert!(matches!(result, Err(PasswordConfirmError::HashIsSentinelValue)));
}
#[test]
fn test_sentinel_value_with_null_bytes_returns_bcrypt_error() {
// The database stores the sentinel "*" in a BINARY(60) column, which pads with null bytes.
// This reproduces the real-world value: "*" followed by 59 null bytes.
// It's currently paging me (until I fix it):
// [2026-03-31T16:03:00Z WARN storyteller_web::http_server::endpoints::users::login_handler] Login hash comparison error: BcryptVerifyError(InvalidHash("*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"))
let mut hash_with_nulls = String::from("*");
for _ in 0..59 {
hash_with_nulls.push('\0');
}
let result = bcrypt_confirm_password("password".to_string(), &hash_with_nulls);
assert!(matches!(result, Err(PasswordConfirmError::HashIsSentinelValue)));
}
}