serde_secrecy/
lib.rs

1//! Serde support for [`secrecy`] types.
2
3#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4
5use secrecy::{ExposeSecret as _, SecretString};
6use serde_core::Serializer;
7
8/// Enables serialization of [`secrecy::SecretString`] fields by exposing the inner string.
9///
10/// # Examples
11///
12/// ```
13/// # use serde::Serialize;
14/// # use secrecy::SecretString;
15/// #[derive(Debug, Serialize)]
16/// struct Login {
17///     #[serde(serialize_with = "serde_secrecy::expose_secret_string")]
18///     password: SecretString,
19/// }
20///
21/// let req = Login {
22///     password: SecretString::from("hunter2"),
23/// };
24///
25/// let json = serde_json::to_string(&req).unwrap();
26/// assert!(json.contains("hunter2"));
27/// ```
28pub fn expose_secret_string<S: Serializer>(
29    secret: &SecretString,
30    ser: S,
31) -> Result<S::Ok, S::Error> {
32    ser.serialize_str(secret.expose_secret())
33}
34
35#[cfg(test)]
36mod tests {
37    use serde::Serialize;
38
39    use super::*;
40
41    #[test]
42    fn serialize_secret_string() {
43        #[derive(Debug, Serialize)]
44        struct Login {
45            email: String,
46            #[serde(serialize_with = "expose_secret_string")]
47            password: SecretString,
48        }
49
50        let req = Login {
51            email: "foo@example.com".to_owned(),
52            password: SecretString::from("hunter2"),
53        };
54
55        let debug = format!("{req:?}");
56        let json = serde_json::to_string(&req).unwrap();
57
58        assert!(debug.contains("example.com"));
59        assert!(json.contains("example.com"));
60
61        assert!(!debug.contains("hunter2"));
62        assert!(json.contains("hunter2"));
63    }
64}