Skip to main content

greentic_operator/
secret_value.rs

1use std::{borrow::Cow, fmt};
2
3#[derive(Clone)]
4pub struct SecretValue<'a> {
5    inner: Cow<'a, [u8]>,
6}
7
8impl<'a> SecretValue<'a> {
9    pub fn new(value: &'a [u8]) -> Self {
10        Self {
11            inner: Cow::Borrowed(value),
12        }
13    }
14
15    pub fn owned(value: Vec<u8>) -> SecretValue<'static> {
16        SecretValue {
17            inner: Cow::Owned(value),
18        }
19    }
20
21    pub fn as_bytes(&self) -> &[u8] {
22        &self.inner
23    }
24
25    pub fn len(&self) -> usize {
26        self.inner.len()
27    }
28
29    pub fn is_empty(&self) -> bool {
30        self.inner.is_empty()
31    }
32}
33
34impl<'a> From<&'a [u8]> for SecretValue<'a> {
35    fn from(value: &'a [u8]) -> Self {
36        Self::new(value)
37    }
38}
39
40impl From<Vec<u8>> for SecretValue<'static> {
41    fn from(value: Vec<u8>) -> Self {
42        Self::owned(value)
43    }
44}
45
46impl fmt::Display for SecretValue<'_> {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        f.write_str("[REDACTED]")
49    }
50}
51
52impl fmt::Debug for SecretValue<'_> {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        f.write_str("[REDACTED]")
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::SecretValue;
61
62    #[test]
63    fn debug_and_display_are_redacted() {
64        let value = SecretValue::new(b"super-secret");
65        assert_eq!(format!("{value}"), "[REDACTED]");
66        assert_eq!(format!("{value:?}"), "[REDACTED]");
67    }
68}