polyoxide_clob/account/
credentials.rs1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Serialize, Deserialize)]
7pub struct Credentials {
8 pub key: String,
9 pub secret: String,
10 pub passphrase: String,
11}
12
13impl fmt::Debug for Credentials {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 f.debug_struct("Credentials")
16 .field("key", &"<redacted>")
17 .field("secret", &"<redacted>")
18 .field("passphrase", &"<redacted>")
19 .finish()
20 }
21}
22
23#[cfg(test)]
24mod tests {
25 use super::*;
26
27 #[test]
28 fn debug_redacts_all_fields() {
29 let creds = Credentials {
30 key: "my-api-key-12345".to_string(),
31 secret: "my-super-secret".to_string(),
32 passphrase: "my-passphrase-xyz".to_string(),
33 };
34 let debug = format!("{:?}", creds);
35
36 assert!(
37 !debug.contains("my-api-key-12345"),
38 "Debug must not leak key: {}",
39 debug
40 );
41 assert!(
42 !debug.contains("my-super-secret"),
43 "Debug must not leak secret: {}",
44 debug
45 );
46 assert!(
47 !debug.contains("my-passphrase-xyz"),
48 "Debug must not leak passphrase: {}",
49 debug
50 );
51 assert!(
52 debug.contains("<redacted>"),
53 "Debug should show <redacted>: {}",
54 debug
55 );
56 }
57
58 #[test]
59 fn credentials_serde_roundtrip() {
60 let original = Credentials {
61 key: "k".to_string(),
62 secret: "s".to_string(),
63 passphrase: "p".to_string(),
64 };
65 let json = serde_json::to_string(&original).unwrap();
66 let deserialized: Credentials = serde_json::from_str(&json).unwrap();
67 assert_eq!(deserialized.key, "k");
68 assert_eq!(deserialized.secret, "s");
69 assert_eq!(deserialized.passphrase, "p");
70 }
71
72 #[test]
73 fn credentials_clone() {
74 let original = Credentials {
75 key: "k".to_string(),
76 secret: "s".to_string(),
77 passphrase: "p".to_string(),
78 };
79 let cloned = original.clone();
80 assert_eq!(cloned.key, original.key);
81 assert_eq!(cloned.secret, original.secret);
82 assert_eq!(cloned.passphrase, original.passphrase);
83 }
84}