betfair_adapter/
secret.rs

1#[derive(Debug, Clone, serde::Deserialize)]
2pub struct SecretProvider {
3    pub application_key: ApplicationKey,
4    pub username: Username,
5    pub password: Password,
6    pub identity: Identity,
7}
8
9#[derive(Debug, Clone, serde::Deserialize)]
10pub struct ApplicationKey(pub redact::Secret<String>);
11
12#[derive(Debug, Clone, serde::Deserialize)]
13pub struct SessionToken(pub redact::Secret<String>);
14
15#[derive(Debug, Clone, serde::Deserialize)]
16pub struct Username(pub redact::Secret<String>);
17
18#[derive(Debug, Clone, serde::Deserialize)]
19pub struct Password(pub redact::Secret<String>);
20
21#[derive(Debug, Clone, serde::Deserialize)]
22pub struct Identity(
23    #[serde(deserialize_with = "serde_utils::deserialize_identity")]
24    pub  redact::Secret<reqwest::Identity>,
25);
26
27impl ApplicationKey {
28    #[must_use]
29    pub const fn new(application_key: String) -> Self {
30        Self(redact::Secret::new(application_key))
31    }
32}
33
34impl Username {
35    #[must_use]
36    pub const fn new(username: String) -> Self {
37        Self(redact::Secret::new(username))
38    }
39}
40impl SessionToken {
41    #[must_use]
42    pub const fn new(username: String) -> Self {
43        Self(redact::Secret::new(username))
44    }
45}
46
47impl Password {
48    #[must_use]
49    pub const fn new(password: String) -> Self {
50        Self(redact::Secret::new(password))
51    }
52}
53
54impl Identity {
55    #[must_use]
56    pub const fn new(identity: reqwest::Identity) -> Self {
57        Self(redact::Secret::new(identity))
58    }
59}
60
61mod serde_utils {
62    use serde::{Deserialize as _, Deserializer};
63
64    pub(crate) fn deserialize_identity<'de, D>(
65        deserializer: D,
66    ) -> Result<redact::Secret<reqwest::Identity>, D::Error>
67    where
68        D: Deserializer<'de>,
69    {
70        let raw_string = String::deserialize(deserializer)?;
71        let identity = reqwest::Identity::from_pem(raw_string.as_bytes())
72            .inspect_err(|err| {
73                tracing::error!(?err, "cannot parse identity");
74            })
75            .map_err(serde::de::Error::custom)?;
76        Ok(redact::Secret::new(identity))
77    }
78}
79#[cfg(test)]
80mod tests {
81
82    use super::*;
83
84    #[test]
85    fn test_deserialize_identity_from_toml() {
86        let toml_str = r#"
87application_key = "some_application_key"
88username = "some_username"
89password = "some_password"
90identity = '''
91-----BEGIN CERTIFICATE-----
92MIIC3zCCAcegAwIBAgIJALAul9kzR0W/MA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNV
93BAYTAmx2MB4XDTIyMDgwMjE5MTE1NloXDTIzMDgwMjE5MTE1NlowDTELMAkGA1UE
94BhMCbHYwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8WWPaghYJcXQp
95W/GAoFqKrQIwxy+h8vdZiURVzzqDKt/Mz45x0Zqj8RVSe4S0lLfkRxcgrLz7ZYSc
96TKsVcur8P66F8A2AJaC4KDiYj4azkTtYQDs+RDLRJUCz5xf/Nw7m+6Y0K7p/p2m8
97bPSm6osefz0orQqpwGogqOwI0FKMkU+BpYjMb+k29xbOec6aHxlaPlHLBPa+n3WC
98V96KwmzSMPEN6Fn/G6PZ5PtwmNg769PiXKk02p+hbnx5OCKvi94mn8vVBGgXF6JR
99Vq9IQQvfFm6G6tf7q+yxMdR2FBR2s03t1daJ3RLGdHzXWTAaNRS7E93OWx+ZyTkd
100kIVM16HTAgMBAAGjQjBAMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgeAMAsG
101A1UdDwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQUFAAOC
102AQEAU/uQHjntyIVR4uQCRoSO5VKyQcXXFY5pbx4ny1yrn0Uxb9P6bOxY5ojcs0r6
103z8ApT3sUfww7kzhle/G5DRtP0cELq7N2YP+qsFx8UO1GYZ5SLj6xm81vk3c0+hrO
104Q3yoS60xKd/7nVsPZ3ch6+9ND0vVUOkefy0aeNix9YgbYjS11rTj7FNiHD25zOJd
105VpZtHkvYDpHcnwUCd0UAuu9ntKKMFGwc9GMqzfY5De6nITvlqzH8YM4AjKO26JsU
1067uMSyHtGF0vvyzhkwCqcuy7r9lQr9m1jTsJ5pSaVasIOJe+/JBUEJm5E4ppdslnW
1071PkfLWOJw34VKkwibWLlwAwTDQ==
108-----END CERTIFICATE-----
109-----BEGIN PRIVATE KEY-----
110MIIEpAIBAAKCAQEAvFlj2oIWCXF0KVvxgKBaiq0CMMcvofL3WYlEVc86gyrfzM+O
111cdGao/EVUnuEtJS35EcXIKy8+2WEnEyrFXLq/D+uhfANgCWguCg4mI+Gs5E7WEA7
112PkQy0SVAs+cX/zcO5vumNCu6f6dpvGz0puqLHn89KK0KqcBqIKjsCNBSjJFPgaWI
113zG/pNvcWznnOmh8ZWj5RywT2vp91glfeisJs0jDxDehZ/xuj2eT7cJjYO+vT4lyp
114NNqfoW58eTgir4veJp/L1QRoFxeiUVavSEEL3xZuhurX+6vssTHUdhQUdrNN7dXW
115id0SxnR811kwGjUUuxPdzlsfmck5HZCFTNeh0wIDAQABAoIBAQCNJFNukCMhanKI
11698xu/js7RlCo6urn6mGvJ+0cfJE1b/CL01HEOzUt+2BmEgetJvDy0M8k/i0UGswY
117MF/YT+iFpNcMqYoEaK4aspFOyedAMuoMxP1gOMz363mkFt3ls4WoVBYFbGtyc6sJ
118t4BSgNpFvUXAcIPYF0ewN8XBCRODH6v7Z6CrbvtjlUXMuU02r5vzMh8a4znIJmZY
11940x6oNIss3YDCGe8J6qMWHByMDZbO63gBoBYayTozzCzl1TG0RZ1oTTL4z36wRto
120uAhjoRek2kiO5axIgKPR/tYlyKzwLkS5v1W09K+pvsabAU6gQlC8kUPk7/+GOaeI
121wGMI9FAZAoGBAOJN8mqJ3zHKvkyFW0uFMU14dl8SVrCZF1VztIooVgnM6bSqNZ3Y
122nKE7wk1DuFjqKAi/mgXTr1v8mQtr40t5dBEMdgDpfRf/RrMfQyhEgQ/m1WqBQtPx
123Suz+EYMpcH05ynrfSbxCDNYM4OHNJ1QfIvHJ/Q9wt5hT7w+MOH5h5TctAoGBANUQ
124cXF4QKU6P+dLUYNjrYP5Wjg4194i0fh/I9NVoUE9Xl22J8l0lybV2phkuODMp1I+
125rBi9AON9skjdCnwtH2ZbRCP6a8Zjv7NMLy4b4dQqfoHwTdCJ0FBfgZXhH4i+AXMb
126XsKotxKGqCWgFKY8LB3UJ0qakK6h9Ze+/zbnZ9z/AoGBAJwrQkD3SAkqakyQMsJY
1279f8KRFWzaBOSciHMKSi2UTmOKTE9zKZTFzPE838yXoMtg9cVsgqXXIpUNKFHIKGy
128/L/PI5fZiTQIPBfcWRHuxEne+CP5c86i0xvc8OTcsf4Y5XwJnu7FfeoxFPd+Bcft
129fMXyqCoBlREPywelsk606+M5AoGAfXLICJJQJbitRYbQQLcgw/K+DxpQ54bC8DgT
130pOvnHR2AAVcuB+xwzrndkhrDzABTiBZEh/BIpKkunr4e3UxID6Eu9qwMZuv2RCBY
131KyLZjW1TvTf66Q0rrRb+mnvJcF7HRbnYym5CFFNaj4S4g8QsCYgPdlqZU2kizCz1
1324aLQQYsCgYAGKytrtHi2BM4Cnnq8Lwd8wT8/1AASIwg2Va1Gcfp00lamuy14O7uz
133yvdFIFrv4ZPdRkf174B1G+FDkH8o3NZ1cf+OuVIKC+jONciIJsYLPTHR0pgWqE4q
134FAbbOyAg51Xklqm2Q954WWFmu3lluHCWUGB9eSHshIurTmDd+8o15A==
135-----END PRIVATE KEY-----'''
136"#;
137
138        let secret_provider: SecretProvider =
139            toml::from_str(toml_str).expect("Failed to deserialize SecretProvider");
140
141        // Assertions to verify that fields are correctly deserialized
142        assert_eq!(
143            secret_provider.application_key.0.expose_secret(),
144            "some_application_key"
145        );
146        assert_eq!(secret_provider.username.0.expose_secret(), "some_username");
147        assert_eq!(secret_provider.password.0.expose_secret(), "some_password");
148    }
149}