pub trait SecretVo: ValueObject {
type Inner;
type Error: Error + Send + Sync + 'static;
// Required methods
fn try_new(inner: Self::Inner) -> Result<Self, Self::Error>;
fn expose_secret(&self) -> &Self::Inner;
}Expand description
A value object that wraps a secret (API key, password, token, …) which must never appear in logs or error messages by accident.
This trait cannot force a redacting Debug impl: ValueObject requires
Debug to exist, but nothing in the type system can require what it
prints. A hand-written impl SecretVo (as in this crate’s own test
fixtures) is only as safe as its own Debug/Display impls - it is the
implementor’s responsibility to redact. #[derive(SecretVo)] in
ddd-toolkit-macro closes this gap for derived types: it always
generates a Debug impl that prints TypeName(***) and never the
wrapped value, so prefer the derive over a manual impl wherever possible.
§Examples
use ddd_toolkit_core::domain::{SecretVo, ValidationError, ValueObject};
use std::fmt::{Debug, Display};
#[derive(Clone, PartialEq)]
struct ApiKey(String);
impl Display for ApiKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[REDACTED]")
}
}
impl Debug for ApiKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ApiKey([REDACTED])")
}
}
impl ValueObject for ApiKey {}
impl SecretVo for ApiKey {
type Inner = String;
type Error = ValidationError;
fn try_new(inner: Self::Inner) -> Result<Self, Self::Error> {
if inner.trim().is_empty() {
return Err(ValidationError::new("ApiKey", "empty"));
}
Ok(Self(inner))
}
fn expose_secret(&self) -> &Self::Inner {
&self.0
}
}
let key = ApiKey::try_new("sk-live-abc123".to_string())?;
// the raw secret is only reachable through the explicit accessor...
assert_eq!(key.expose_secret(), "sk-live-abc123");
// ...never through Display/Debug, so it can't leak into a log by accident.
assert_eq!(key.to_string(), "[REDACTED]");
assert_eq!(format!("{key:?}"), "ApiKey([REDACTED])");Required Associated Types§
Required Methods§
Sourcefn try_new(inner: Self::Inner) -> Result<Self, Self::Error>
fn try_new(inner: Self::Inner) -> Result<Self, Self::Error>
Validates and wraps inner.
§Errors
Returns SecretVo::Error if inner fails the implementation’s
validation.
Sourcefn expose_secret(&self) -> &Self::Inner
fn expose_secret(&self) -> &Self::Inner
Returns the wrapped secret. Named to make call sites (key.expose_secret()
rather than key.0) an explicit, greppable signal that a secret is
about to be handled directly.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".