Skip to main content

api_testing_core/
redact.rs

1use crate::Result;
2
3pub const REDACTED: &str = "<REDACTED>";
4
5fn should_redact_key(key: &str) -> bool {
6    let k = key.trim().to_ascii_lowercase();
7    matches!(
8        k.as_str(),
9        "accesstoken"
10            | "access_token"
11            | "refreshtoken"
12            | "refresh_token"
13            | "password"
14            | "token"
15            | "apikey"
16            | "api_key"
17            | "authorization"
18            | "cookie"
19            | "set-cookie"
20    )
21}
22
23fn redact_value(value: &mut serde_json::Value) {
24    *value = serde_json::Value::String(REDACTED.to_string());
25}
26
27fn redact_in_json(value: &mut serde_json::Value) {
28    match value {
29        serde_json::Value::Object(map) => {
30            for (k, v) in map.iter_mut() {
31                if should_redact_key(k) {
32                    redact_value(v);
33                } else {
34                    redact_in_json(v);
35                }
36            }
37        }
38        serde_json::Value::Array(values) => {
39            for v in values {
40                redact_in_json(v);
41            }
42        }
43        _ => {}
44    }
45}
46
47/// Apply default redaction rules to a JSON value in-place.
48///
49/// This is shared between REST and GraphQL report generation and history snippets.
50pub fn redact_json(value: &mut serde_json::Value) -> Result<()> {
51    redact_in_json(value);
52    Ok(())
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58    use pretty_assertions::assert_eq;
59
60    #[test]
61    fn redact_replaces_common_secret_fields_recursively() {
62        let mut v = serde_json::json!({
63            "accessToken": "a",
64            "access_token": "a2",
65            "refreshToken": "b",
66            "refresh_token": "b2",
67            "password": "c",
68            "token": "d",
69            "apiKey": "e",
70            "api_key": "e2",
71            "authorization": "Bearer x",
72            "cookie": "a=b",
73            "set-cookie": "c=d",
74            "nested": {
75                "Authorization": "Bearer y",
76                "ok": "keep"
77            },
78            "arr": [
79                {"token": "t"},
80                {"ok": 1}
81            ]
82        });
83
84        redact_json(&mut v).unwrap();
85
86        assert_eq!(v["accessToken"], REDACTED);
87        assert_eq!(v["access_token"], REDACTED);
88        assert_eq!(v["refreshToken"], REDACTED);
89        assert_eq!(v["refresh_token"], REDACTED);
90        assert_eq!(v["password"], REDACTED);
91        assert_eq!(v["token"], REDACTED);
92        assert_eq!(v["apiKey"], REDACTED);
93        assert_eq!(v["api_key"], REDACTED);
94        assert_eq!(v["authorization"], REDACTED);
95        assert_eq!(v["cookie"], REDACTED);
96        assert_eq!(v["set-cookie"], REDACTED);
97        assert_eq!(v["nested"]["Authorization"], REDACTED);
98        assert_eq!(v["nested"]["ok"], "keep");
99        assert_eq!(v["arr"][0]["token"], REDACTED);
100        assert_eq!(v["arr"][1]["ok"], 1);
101    }
102}