libvault_rs/secrets/key_value/
requests.rs1use super::responses::{KeyValueResponse, KeyValueV1Response, KeyValueV2Response};
2use crate::client::vault::{AuthenticatedVaultClient, VaultClientError};
3
4pub enum KeyValueVersion {
5 One,
6 Two,
7}
8
9pub struct KeyValue {
10 version: KeyValueVersion,
11 mount: String,
12}
13
14impl KeyValue {
15 pub fn new(version: KeyValueVersion, mount: impl Into<String>) -> Self {
16 Self {
17 version,
18 mount: mount.into(),
19 }
20 }
21
22 pub async fn read(
23 &self,
24 vault_client: &AuthenticatedVaultClient,
25 path: &str,
26 ) -> Result<KeyValueResponse, VaultClientError> {
27 let response = vault_client
28 .client
29 .read(
30 self.url(vault_client.client.base_url(), path),
31 Some(vault_client.token.clone()),
32 )
33 .await;
34
35 match response {
36 Err(e) => Err(e),
37 Ok(value) => {
38 match self.version {
39 KeyValueVersion::One => {
40 let convert: Result<KeyValueV1Response, serde_json::Error> =
41 serde_json::from_value(value);
42 match convert {
43 Ok(value) => Ok(KeyValueResponse::new(value.data)),
44 Err(e) => Err(VaultClientError::new(e.to_string())),
45 }
46 }
47 KeyValueVersion::Two => {
48 let convert: Result<KeyValueV2Response, serde_json::Error> =
49 serde_json::from_value(value);
50 match convert {
51 Ok(value) => Ok(KeyValueResponse::new(value.data.data)),
52 Err(e) => Err(VaultClientError::new(e.to_string())),
53 }
54 }
55 }
56 },
57 }
58 }
59
60 fn url(&self, base_url: String, path: &str) -> String {
61 match self.version {
62 KeyValueVersion::One => format!("{}/{}/{}", base_url, self.mount, path),
63 KeyValueVersion::Two => format!("{}/{}/data/{}", base_url, self.mount, path),
64 }
65 }
66}
67
68#[cfg(test)]
69mod test {
70 use super::{KeyValue, KeyValueVersion};
71 use crate::{
72 client::vault::{AuthenticatedVaultClient, Parameters, VaultClient, VaultClientError},
73 secrets::key_value::{
74 test_helpers::{
75 successful_key_value_response, successful_v1_json_response,
76 successful_v2_json_response,
77 },
78 },
79 };
80 use futures::{future::BoxFuture, FutureExt};
81 use serde_json::json;
82
83
84 struct StubClient {
85 response: serde_json::Value,
86 }
87
88 impl VaultClient for StubClient {
89 fn read(&self, _: String, _: Option<String>) -> BoxFuture<Result<serde_json::Value, VaultClientError>> {
90 async { Ok(self.response.to_owned()) }.boxed()
91 }
92
93 fn create(&self, _: String, _: Option<String>, _: Parameters) -> BoxFuture<Result<serde_json::Value, VaultClientError>> {
94 unimplemented!()
95 }
96
97 fn base_url(&self) -> String {
98 "test".into()
99 }
100 }
101
102 #[tokio::test]
103 async fn v1_success() {
104 let vault_client: StubClient = StubClient {
105 response: successful_v1_json_response(),
106 };
107 let key_value: KeyValue = KeyValue::new(KeyValueVersion::One, "secrets");
108 let authenticated_client: AuthenticatedVaultClient =
109 AuthenticatedVaultClient::new(Box::new(vault_client), "token".into());
110
111 assert_eq!(
112 Ok(successful_key_value_response()),
113 key_value.read(&authenticated_client, "test").await
114 );
115 }
116
117 #[tokio::test]
118 async fn v2_success() {
119 let vault_client: StubClient = StubClient {
120 response: successful_v2_json_response(),
121 };
122 let key_value: KeyValue = KeyValue::new(KeyValueVersion::Two, "secrets");
123 let authenticated_client: AuthenticatedVaultClient =
124 AuthenticatedVaultClient::new(Box::new(vault_client), "token".into());
125
126 assert_eq!(
127 Ok(successful_key_value_response()),
128 key_value.read(&authenticated_client, "test").await
129 );
130 }
131
132 #[tokio::test]
133 async fn v1_deserialization_failure() {
134 let vault_client: StubClient = StubClient {
135 response: json!({}),
136 };
137 let key_value: KeyValue = KeyValue::new(KeyValueVersion::One, "secrets");
138 let authenticated_client: AuthenticatedVaultClient =
139 AuthenticatedVaultClient::new(Box::new(vault_client), "token".into());
140
141 assert_eq!(
142 Err(VaultClientError::new("missing field `data`".into())),
143 key_value.read(&authenticated_client, "test").await
144 );
145 }
146
147 #[tokio::test]
148 async fn v2_deserialization_failure() {
149 let vault_client: StubClient = StubClient {
150 response: json!({}),
151 };
152 let key_value: KeyValue = KeyValue::new(KeyValueVersion::Two, "secrets");
153 let authenticated_client: AuthenticatedVaultClient =
154 AuthenticatedVaultClient::new(Box::new(vault_client), "token".into());
155
156 assert_eq!(
157 Err(VaultClientError::new("missing field `data`".into())),
158 key_value.read(&authenticated_client, "test").await
159 );
160 }
161}