use secrecy::{ExposeSecret, SecretString};
use subtle::ConstantTimeEq;
pub type SecureString = SecretString;
pub trait SecureStringExt {
fn len(&self) -> usize;
fn is_empty(&self) -> bool;
fn eq(&self, other: &Self) -> bool;
}
impl SecureStringExt for SecureString {
fn len(&self) -> usize {
self.expose_secret().len()
}
fn is_empty(&self) -> bool {
self.expose_secret().is_empty()
}
fn eq(&self, other: &Self) -> bool {
self.expose_secret()
.as_bytes()
.ct_eq(other.expose_secret().as_bytes())
.into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_secure_string_creation() {
let secret = SecretString::from("my_secret");
assert_eq!(secret.expose_secret(), "my_secret");
assert_eq!(secret.len(), 9);
assert!(!secret.is_empty());
}
#[test]
fn test_secure_string_redaction() {
let secret = SecretString::from("sensitive_data");
let debug_output = format!("{:?}", secret);
assert!(!debug_output.contains("sensitive_data"));
assert!(debug_output.contains("Secret"));
}
#[test]
fn test_secure_string_empty() {
let empty = SecretString::from("");
assert!(empty.is_empty());
assert_eq!(empty.len(), 0);
}
#[test]
fn test_expose_secret() {
let secret = SecretString::from("test".to_string());
let reference: &str = secret.expose_secret();
assert_eq!(reference, "test");
}
}