cloud_storage_rs/resources/hmac_key.rs
1use crate::error::GoogleResponse;
2
3/// The `HmacKey` resource represents an HMAC key within Cloud Storage. The resource consists of a
4/// secret and `HmacMeta`. HMAC keys can be used as credentials for service accounts. For more
5/// information, see HMAC Keys.
6///
7/// Note that the `HmacKey` resource is only returned when you use `HmacKey::create`. Other
8/// methods, such as `HmacKey::read`, return the metadata portion of the HMAC key resource.
9#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct HmacKey {
12 /// The kind of item this is. For HMAC keys, this is always `storage#hmacKey`.
13 pub kind: String,
14 /// HMAC key metadata.
15 pub metadata: HmacMeta,
16 /// HMAC secret key material.
17 pub secret: String,
18}
19
20/// Contains information about an Hmac Key.
21#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub struct HmacMeta {
24 /// The kind of item this is. For HMAC key metadata, this is always `storage#hmacKeyMetadata`.
25 pub kind: String,
26 /// The ID of the HMAC key, including the Project ID and the Access ID.
27 pub id: String,
28 /// The link to this resource.
29 pub self_link: String,
30 /// The access ID of the HMAC Key.
31 pub access_id: String,
32 /// The Project ID of the project that owns the service account to which the key authenticates.
33 pub project_id: String,
34 /// The email address of the key's associated service account.
35 pub service_account_email: String,
36 /// The state of the key.
37 pub state: HmacState,
38 /// The creation time of the HMAC key.
39 pub time_created: chrono::DateTime<chrono::Utc>,
40 /// The last modification time of the HMAC key metadata.
41 pub updated: chrono::DateTime<chrono::Utc>,
42 /// HTTP 1.1 Entity tag for the HMAC key.
43 pub etag: String,
44}
45
46/// The state of an Hmac Key.
47#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
48#[serde(rename_all = "UPPERCASE")]
49pub enum HmacState {
50 /// This Hmac key is currently used.
51 Active,
52 /// This Hmac key has been set to inactive.
53 Inactive,
54 /// This Hmac key has been permanently deleted.
55 Deleted,
56}
57
58#[derive(serde::Deserialize)]
59struct ListResponse {
60 items: Vec<HmacMeta>,
61}
62
63#[derive(serde::Serialize)]
64struct UpdateRequest {
65 secret: String,
66 metadata: UpdateMeta,
67}
68
69#[derive(serde::Serialize)]
70struct UpdateMeta {
71 state: HmacState,
72}
73
74impl HmacKey {
75 /// Creates a new HMAC key for the specified service account.
76 ///
77 /// The authenticated user must have `storage.hmacKeys.create` permission for the project in
78 /// which the key will be created.
79 ///
80 /// For general information about HMAC keys in Cloud Storage, see
81 /// [HMAC Keys](https://cloud.google.com/storage/docs/authentication/hmackeys).
82 /// ### Example
83 /// ```
84 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
85 /// use cloud_storage::hmac_key::HmacKey;
86 ///
87 /// let hmac_key = HmacKey::create()?;
88 /// # use cloud_storage::hmac_key::HmacState;
89 /// # HmacKey::update(&hmac_key.metadata.access_id, HmacState::Inactive)?;
90 /// # HmacKey::delete(&hmac_key.metadata.access_id)?;
91 /// # Ok(())
92 /// # }
93 /// ```
94 pub fn create() -> Result<Self, crate::Error> {
95 use reqwest::header::CONTENT_LENGTH;
96
97 let url = format!(
98 "{}/projects/{}/hmacKeys",
99 crate::BASE_URL,
100 crate::SERVICE_ACCOUNT.project_id
101 );
102 let query = [("serviceAccountEmail", &crate::SERVICE_ACCOUNT.client_email)];
103 let mut headers = crate::get_headers()?;
104 headers.insert(CONTENT_LENGTH, 0.into());
105 let client = reqwest::blocking::Client::new();
106 let result: GoogleResponse<Self> = client
107 .post(&url)
108 .headers(headers)
109 .query(&query)
110 .send()?
111 .json()?;
112 match result {
113 GoogleResponse::Success(s) => Ok(s),
114 GoogleResponse::Error(e) => Err(e.into()),
115 }
116 }
117
118 /// Retrieves a list of HMAC keys matching the criteria. Since the HmacKey is secret, this does
119 /// not return a `HmacKey`, but a `HmacMeta`. This is a redacted version of a `HmacKey`, but
120 /// with the secret data omitted.
121 ///
122 /// The authenticated user must have `storage.hmacKeys.list` permission for the project in which
123 /// the key exists.
124 ///
125 /// For general information about HMAC keys in Cloud Storage, see
126 /// [HMAC Keys](https://cloud.google.com/storage/docs/authentication/hmackeys).
127 /// ### Example
128 /// ```
129 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
130 /// use cloud_storage::hmac_key::HmacKey;
131 ///
132 /// let all_hmac_keys = HmacKey::list()?;
133 /// # Ok(())
134 /// # }
135 /// ```
136 pub fn list() -> Result<Vec<HmacMeta>, crate::Error> {
137 let url = format!(
138 "{}/projects/{}/hmacKeys",
139 crate::BASE_URL,
140 crate::SERVICE_ACCOUNT.project_id
141 );
142 let client = reqwest::blocking::Client::new();
143 let result: GoogleResponse<ListResponse> = client
144 .get(&url)
145 .headers(crate::get_headers()?)
146 .send()?
147 .json()?;
148 match result {
149 GoogleResponse::Success(s) => Ok(s.items),
150 GoogleResponse::Error(e) => Err(e.into()),
151 }
152 }
153
154 /// Retrieves an HMAC key's metadata. Since the HmacKey is secret, this does not return a
155 /// `HmacKey`, but a `HmacMeta`. This is a redacted version of a `HmacKey`, but with the secret
156 /// data omitted.
157 ///
158 /// The authenticated user must have `storage.hmacKeys.get` permission for the project in which
159 /// the key exists.
160 ///
161 /// For general information about HMAC keys in Cloud Storage, see
162 /// [HMAC Keys](https://cloud.google.com/storage/docs/authentication/hmackeys).
163 /// ### Example
164 /// ```no_run
165 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
166 /// use cloud_storage::hmac_key::HmacKey;
167 ///
168 /// let key = HmacKey::read("some identifier")?;
169 /// # Ok(())
170 /// # }
171 pub fn read(access_id: &str) -> Result<HmacMeta, crate::Error> {
172 let url = format!(
173 "{}/projects/{}/hmacKeys/{}",
174 crate::BASE_URL,
175 crate::SERVICE_ACCOUNT.project_id,
176 access_id
177 );
178 let client = reqwest::blocking::Client::new();
179 let result: GoogleResponse<HmacMeta> = client
180 .get(&url)
181 .headers(crate::get_headers()?)
182 .send()?
183 .json()?;
184 match result {
185 GoogleResponse::Success(s) => Ok(s),
186 GoogleResponse::Error(e) => Err(e.into()),
187 }
188 }
189
190 /// Updates the state of an HMAC key. See the HMAC Key resource descriptor for valid states.
191 /// Since the HmacKey is secret, this does not return a `HmacKey`, but a `HmacMeta`. This is a
192 /// redacted version of a `HmacKey`, but with the secret data omitted.
193 ///
194 /// The authenticated user must have `storage.hmacKeys.update` permission for the project in
195 /// which the key exists.
196 ///
197 /// For general information about HMAC keys in Cloud Storage, see
198 /// [HMAC Keys](https://cloud.google.com/storage/docs/authentication/hmackeys).
199 /// ### Example
200 /// ```no_run
201 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
202 /// use cloud_storage::hmac_key::{HmacKey, HmacState};
203 ///
204 /// let key = HmacKey::update("your key", HmacState::Active)?;
205 /// # Ok(())
206 /// # }
207 pub fn update(access_id: &str, state: HmacState) -> Result<HmacMeta, crate::Error> {
208 let url = format!(
209 "{}/projects/{}/hmacKeys/{}",
210 crate::BASE_URL,
211 crate::SERVICE_ACCOUNT.project_id,
212 access_id
213 );
214 let client = reqwest::blocking::Client::new();
215 serde_json::to_string(&UpdateMeta { state })?;
216 let result: GoogleResponse<HmacMeta> = client
217 .put(&url)
218 .headers(crate::get_headers()?)
219 .json(&UpdateMeta { state })
220 .send()?
221 .json()?;
222 match result {
223 GoogleResponse::Success(s) => Ok(s),
224 GoogleResponse::Error(e) => Err(e.into()),
225 }
226 }
227
228 /// Deletes an HMAC key. Note that a key must be set to `Inactive` first.
229 ///
230 /// The authenticated user must have storage.hmacKeys.delete permission for the project in which
231 /// the key exists.
232 ///
233 /// For general information about HMAC keys in Cloud Storage, see
234 /// [HMAC Keys](https://cloud.google.com/storage/docs/authentication/hmackeys).
235 /// ### Example
236 /// ```no_run
237 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
238 /// use cloud_storage::hmac_key::{HmacKey, HmacState};
239 ///
240 /// let key = HmacKey::update("your key", HmacState::Inactive)?; // this is required.
241 /// HmacKey::delete(&key.access_id)?;
242 /// # Ok(())
243 /// # }
244 pub fn delete(access_id: &str) -> Result<(), crate::Error> {
245 let url = format!(
246 "{}/projects/{}/hmacKeys/{}",
247 crate::BASE_URL,
248 crate::SERVICE_ACCOUNT.project_id,
249 access_id
250 );
251 let client = reqwest::blocking::Client::new();
252 let response = client.delete(&url).headers(crate::get_headers()?).send()?;
253 if response.status().is_success() {
254 Ok(())
255 } else {
256 Err(crate::Error::Google(response.json()?))
257 }
258 }
259}
260
261#[cfg(test)]
262mod tests {
263 use super::*;
264
265 fn get_test_hmac() -> HmacMeta {
266 match HmacKey::create() {
267 Ok(key) => key.metadata,
268 Err(_) => HmacKey::list().unwrap().pop().unwrap(),
269 }
270 }
271
272 fn remove_test_hmac(access_id: &str) {
273 HmacKey::update(access_id, HmacState::Inactive).unwrap();
274 HmacKey::delete(access_id).unwrap();
275 }
276
277 #[test]
278 fn create() -> Result<(), Box<dyn std::error::Error>> {
279 let key = HmacKey::create()?;
280 remove_test_hmac(&key.metadata.access_id);
281 Ok(())
282 }
283
284 #[test]
285 fn list() -> Result<(), Box<dyn std::error::Error>> {
286 HmacKey::list()?;
287 Ok(())
288 }
289
290 #[test]
291 fn read() -> Result<(), Box<dyn std::error::Error>> {
292 let key = get_test_hmac();
293 HmacKey::read(&key.access_id)?;
294 remove_test_hmac(&key.access_id);
295 Ok(())
296 }
297
298 #[test]
299 fn update() -> Result<(), Box<dyn std::error::Error>> {
300 let key = get_test_hmac();
301 HmacKey::update(&key.access_id, HmacState::Inactive)?;
302 HmacKey::delete(&key.access_id)?;
303 Ok(())
304 }
305
306
307 #[test]
308 fn delete() -> Result<(), Box<dyn std::error::Error>> {
309 let key = get_test_hmac();
310 HmacKey::update(&key.access_id, HmacState::Inactive)?;
311 HmacKey::delete(&key.access_id)?;
312 Ok(())
313 }
314}