use crate::errors::{AshError, AshErrorCode, InternalReason};
const MIN_NONCE_HEX_CHARS: usize = 32;
const MAX_NONCE_LENGTH: usize = 512;
pub fn ash_validate_nonce(nonce: &str) -> Result<(), AshError> {
if nonce.len() < MIN_NONCE_HEX_CHARS {
return Err(AshError::with_reason(
AshErrorCode::ValidationError,
InternalReason::NonceTooShort,
format!(
"Nonce must be at least {} hex characters ({} bytes) for adequate entropy",
MIN_NONCE_HEX_CHARS,
MIN_NONCE_HEX_CHARS / 2
),
));
}
if nonce.len() > MAX_NONCE_LENGTH {
return Err(AshError::with_reason(
AshErrorCode::ValidationError,
InternalReason::NonceTooLong,
format!("Nonce exceeds maximum length of {} characters", MAX_NONCE_LENGTH),
));
}
if !nonce.chars().all(|c| c.is_ascii_hexdigit()) {
return Err(AshError::with_reason(
AshErrorCode::ValidationError,
InternalReason::NonceInvalidChars,
"Nonce must contain only hexadecimal characters (0-9, a-f, A-F)",
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_nonce_valid_32_chars() {
assert!(ash_validate_nonce("0123456789abcdef0123456789abcdef").is_ok());
}
#[test]
fn test_nonce_valid_64_chars() {
let nonce = "a".repeat(64);
assert!(ash_validate_nonce(&nonce).is_ok());
}
#[test]
fn test_nonce_valid_512_chars() {
let nonce = "f".repeat(512);
assert!(ash_validate_nonce(&nonce).is_ok());
}
#[test]
fn test_nonce_too_short() {
let err = ash_validate_nonce("abcdef").unwrap_err();
assert_eq!(err.code(), AshErrorCode::ValidationError);
assert_eq!(err.http_status(), 485);
assert_eq!(err.reason(), InternalReason::NonceTooShort);
}
#[test]
fn test_nonce_empty() {
let err = ash_validate_nonce("").unwrap_err();
assert_eq!(err.reason(), InternalReason::NonceTooShort);
}
#[test]
fn test_nonce_too_long() {
let nonce = "a".repeat(513);
let err = ash_validate_nonce(&nonce).unwrap_err();
assert_eq!(err.code(), AshErrorCode::ValidationError);
assert_eq!(err.http_status(), 485);
assert_eq!(err.reason(), InternalReason::NonceTooLong);
}
#[test]
fn test_nonce_invalid_chars() {
let err = ash_validate_nonce("0123456789abcdef0123456789abcdXY").unwrap_err();
assert_eq!(err.code(), AshErrorCode::ValidationError);
assert_eq!(err.http_status(), 485);
assert_eq!(err.reason(), InternalReason::NonceInvalidChars);
}
#[test]
fn test_nonce_uppercase_hex_valid() {
assert!(ash_validate_nonce("0123456789ABCDEF0123456789ABCDEF").is_ok());
}
#[test]
fn test_nonce_boundary_31_chars() {
let nonce = "a".repeat(31);
assert!(ash_validate_nonce(&nonce).is_err());
}
#[test]
fn test_nonce_boundary_32_chars() {
let nonce = "a".repeat(32);
assert!(ash_validate_nonce(&nonce).is_ok());
}
}