rusty_oss/credentials/
serde.rs1use std::fmt::{self, Debug, Formatter};
2use std::mem;
3
4use serde::{Deserialize, Deserializer};
5use time::PrimitiveDateTime;
6use zeroize::Zeroize as _;
7
8use crate::time_::ISO8601_EXT;
9
10use super::{Credentials, RotatingCredentials};
11
12#[derive(Clone, Deserialize)]
14pub struct EcsSecurityCredentialsMetadataResponse {
15 #[serde(rename = "AccessKeyId")]
16 key: String,
17 #[serde(rename = "AccessKeySecret")]
18 secret: String,
19 #[serde(rename = "SecurityToken")]
20 token: String,
21 #[serde(rename = "Expiration", deserialize_with = "expiration_deserializer")]
22 expiration: PrimitiveDateTime,
23}
24
25fn expiration_deserializer<'de, D>(deserializer: D) -> Result<PrimitiveDateTime, D::Error>
26where
27 D: Deserializer<'de>,
28{
29 let s: &str = Deserialize::deserialize(deserializer)?;
30
31 PrimitiveDateTime::parse(s, &ISO8601_EXT).map_err(serde::de::Error::custom)
32}
33
34impl EcsSecurityCredentialsMetadataResponse {
35 pub fn deserialize(s: &str) -> Result<Self, serde_json::Error> {
44 serde_json::from_str(s)
45 }
46
47 #[inline]
49 #[must_use]
50 pub fn key(&self) -> &str {
51 &self.key
52 }
53
54 #[inline]
56 #[must_use]
57 pub fn secret(&self) -> &str {
58 &self.secret
59 }
60
61 #[inline]
63 #[must_use]
64 pub fn token(&self) -> &str {
65 &self.token
66 }
67
68 #[inline]
70 #[must_use]
71 pub const fn expiration(&self) -> PrimitiveDateTime {
72 self.expiration
73 }
74
75 #[inline]
77 #[must_use]
78 pub fn into_credentials(mut self) -> Credentials {
79 let key = mem::take(&mut self.key);
80 let secret = mem::take(&mut self.secret);
81 let token = mem::take(&mut self.token);
82 Credentials::new_with_token(key, secret, token)
83 }
84
85 #[inline]
87 pub fn rotate_credentials(mut self, rotating: &RotatingCredentials) {
88 let key = mem::take(&mut self.key);
89 let secret = mem::take(&mut self.secret);
90 let token = mem::take(&mut self.token);
91 rotating.update(key, secret, Some(token));
92 }
93}
94
95impl Debug for EcsSecurityCredentialsMetadataResponse {
96 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
97 f.debug_struct("EcsSecurityCredentialsMetadataResponse")
98 .field("key", &self.key)
99 .finish_non_exhaustive()
100 }
101}
102
103impl Drop for EcsSecurityCredentialsMetadataResponse {
104 fn drop(&mut self) {
105 self.secret.zeroize();
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use pretty_assertions::assert_eq;
112
113 use super::*;
114
115 #[test]
116 fn deserialize() {
117 let json = r#"{
118 "Code" : "Success",
119 "LastUpdated" : "2020-12-28T16:47:50Z",
120 "Type" : "OSS-HMAC",
121 "AccessKeyId" : "some_access_key",
122 "AccessKeySecret" : "some_secret_key",
123 "SecurityToken" : "some_token",
124 "Expiration" : "2020-12-28T23:10:09Z"
125}"#;
126
127 let deserialized = EcsSecurityCredentialsMetadataResponse::deserialize(json).unwrap();
128 assert_eq!(deserialized.key(), "some_access_key");
129 assert_eq!(deserialized.secret(), "some_secret_key");
130 assert_eq!(deserialized.token(), "some_token");
131 assert_eq!(
133 deserialized.expiration().assume_utc().unix_timestamp(),
134 1609197009
135 );
136
137 let debug_output = format!("{deserialized:?}");
138 assert_eq!(
139 debug_output,
140 "EcsSecurityCredentialsMetadataResponse { key: \"some_access_key\", .. }"
141 );
142 }
143}