use std::fmt;
use crate::SecretString;
#[derive(Clone)]
pub struct AppPassword {
user: String,
password: SecretString,
}
impl AppPassword {
pub fn new(user: impl Into<String>, password: SecretString) -> Self {
Self {
user: user.into(),
password,
}
}
pub fn user(&self) -> &str {
&self.user
}
pub fn password(&self) -> &SecretString {
&self.password
}
}
impl fmt::Debug for AppPassword {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AppPassword")
.field("user", &self.user)
.field("password", &self.password)
.finish()
}
}
#[cfg(test)]
mod tests {
use super::AppPassword;
use crate::SecretString;
#[test]
fn debug_redacts_the_password() {
let credentials = AppPassword::new("alice", SecretString::new("s3cr3t-app-password"));
let rendered = format!("{credentials:?}");
assert!(!rendered.contains("s3cr3t-app-password"));
assert!(rendered.contains("<redacted>"));
assert!(rendered.contains("alice"));
}
#[test]
fn exposes_user_and_password() {
let credentials = AppPassword::new("alice", SecretString::new("pw"));
assert_eq!(credentials.user(), "alice");
assert_eq!(credentials.password().expose(), "pw");
}
}