redact/
serde.rs

1use crate::Secret;
2
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4
5/// *This API requires the following crate features to be activated: `serde`*
6impl<'de, T: Deserialize<'de>> Deserialize<'de> for Secret<T> {
7    #[inline]
8    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
9        T::deserialize(deserializer).map(Self)
10    }
11}
12
13/// A serializable type that contains a secret.
14///
15/// This abstraction enables [expose_secret] to be used to serialize both `Secret<T>`, `&Secret<T>`,
16/// `Option<Secret<T>>` and `Vec<Secret<T>>`.
17pub trait SerializableSecret<T> {
18    type Exposed<'a>: Serialize
19    where
20        Self: 'a;
21    /// To reduce the number of functions that are able to expose secrets we require
22    /// that the [`Secret::expose_secret`] function is passed in here.
23    fn expose_via(&self, expose: impl Fn(&Secret<T>) -> &T) -> Self::Exposed<'_>;
24}
25
26impl<T: Serialize> SerializableSecret<T> for &Secret<T> {
27    type Exposed<'a>
28        = &'a T
29    where
30        T: 'a,
31        Self: 'a;
32
33    fn expose_via(&self, expose: impl Fn(&Secret<T>) -> &T) -> Self::Exposed<'_> {
34        expose(self)
35    }
36}
37
38impl<T: Serialize> SerializableSecret<T> for Secret<T> {
39    type Exposed<'a>
40        = &'a T
41    where
42        T: 'a;
43
44    fn expose_via(&self, expose: impl Fn(&Secret<T>) -> &T) -> Self::Exposed<'_> {
45        expose(self)
46    }
47}
48
49impl<T: Serialize> SerializableSecret<T> for Option<Secret<T>> {
50    type Exposed<'a>
51        = Option<&'a T>
52    where
53        T: 'a;
54
55    fn expose_via(&self, expose: impl Fn(&Secret<T>) -> &T) -> Self::Exposed<'_> {
56        self.as_ref().map(expose)
57    }
58}
59
60#[cfg(feature = "std")]
61impl<T: Serialize> SerializableSecret<T> for Vec<Secret<T>>
62where
63    for<'a> Vec<&'a T>: Serialize,
64{
65    type Exposed<'a>
66        = Vec<&'a T>
67    where
68        T: 'a;
69
70    fn expose_via(&self, expose: impl Fn(&Secret<T>) -> &T) -> Self::Exposed<'_> {
71        self.iter().map(expose).collect()
72    }
73}
74
75/// Exposes a [Secret] for serialization.
76///
77/// For general-purpose secret exposing see [Secret::expose_secret].
78///
79/// See [module level documentation][crate] for usage example.
80///
81/// *This API requires the following crate features to be activated: `serde`*
82#[cfg(feature = "serde")]
83#[inline]
84pub fn expose_secret<S: Serializer, T: Serialize>(
85    secret: &impl SerializableSecret<T>,
86    serializer: S,
87) -> Result<S::Ok, S::Error> {
88    secret
89        .expose_via(Secret::expose_secret)
90        .serialize(serializer)
91}
92
93/// Serialize a redacted [Secret] without exposing the contained data.
94///
95/// The secret will be serialized as its [`Debug`] output.
96/// Since the data is redacted, it is not possible to deserialize data serialized in this way.
97///
98/// This function is designed to be used with `#[serde(serialize_with)]` in the same way as
99/// [serde::expose_secret][crate::serde::expose_secret].
100///
101/// *This API requires the following crate features to be activated: `serde`*
102#[cfg(feature = "serde")]
103#[inline]
104pub fn redact_secret<S: Serializer, T>(
105    secret: &Secret<T>,
106    serializer: S,
107) -> Result<S::Ok, S::Error> {
108    serializer.collect_str(&format_args!("{secret:?}"))
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use fake::{Fake, Faker};
115    use serde::{Deserialize, Serialize};
116
117    #[test]
118    fn deserialize_the_serialized() {
119        #[derive(Serialize, Deserialize, fake::Dummy, PartialEq, Debug)]
120        struct Test {
121            #[serde(serialize_with = "expose_secret")]
122            one: Secret<String>,
123            #[serde(serialize_with = "expose_secret")]
124            two: Option<Secret<String>>,
125            #[serde(serialize_with = "expose_secret")]
126            three: Vec<Secret<String>>,
127        }
128
129        let to_serialize: Test = Faker.fake();
130
131        let serialized = serde_json::to_string(&to_serialize).unwrap();
132
133        let deserialized = serde_json::from_str(&serialized).unwrap();
134
135        assert_eq!(to_serialize, deserialized)
136    }
137}