#[inline]
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut diff = 0u8;
for (x, y) in a.iter().zip(b.iter()) {
diff |= x ^ y;
}
diff == 0
}
#[inline]
pub fn verify_token(configured: &str, presented: &str) -> bool {
constant_time_eq(configured.as_bytes(), presented.as_bytes())
}
pub fn is_loopback_host(host: &str) -> bool {
if host.eq_ignore_ascii_case("localhost") {
return true;
}
host.parse::<std::net::IpAddr>()
.map(|ip| ip.is_loopback())
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_time_eq() {
assert!(constant_time_eq(b"secret", b"secret"));
assert!(!constant_time_eq(b"secret", b"secreu"));
assert!(!constant_time_eq(b"secret", b"secr"));
assert!(constant_time_eq(b"", b""));
}
#[test]
fn test_verify_token() {
assert!(verify_token("hunter2", "hunter2"));
assert!(!verify_token("hunter2", "Hunter2"));
assert!(!verify_token("hunter2", ""));
}
#[test]
fn test_is_loopback_host() {
assert!(is_loopback_host("127.0.0.1"));
assert!(is_loopback_host("::1"));
assert!(is_loopback_host("localhost"));
assert!(is_loopback_host("LOCALHOST"));
assert!(!is_loopback_host("0.0.0.0"));
assert!(!is_loopback_host("::"));
assert!(!is_loopback_host("192.168.1.10"));
assert!(!is_loopback_host("example.com"));
}
}