betfair_adapter/
secret.rs1#[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 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}