bitwarden_api_key_connector/apis/
user_keys_api.rs

1use std::sync::Arc;
2
3use async_trait::async_trait;
4use bitwarden_api_base::{AuthRequired, Configuration};
5use mockall::automock;
6use reqwest::Method;
7use serde::Serialize;
8
9use crate::{
10    apis::Error,
11    models::{
12        user_key_request_model::UserKeyKeyRequestModel,
13        user_key_response_model::UserKeyResponseModel,
14    },
15};
16
17#[automock]
18#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
19#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
20pub trait UserKeysApi: Send + Sync {
21    /// GET /user-keys
22    async fn get_user_key(&self) -> Result<UserKeyResponseModel, Error>;
23
24    /// POST /user-keys
25    async fn post_user_key(&self, request_model: UserKeyKeyRequestModel) -> Result<(), Error>;
26
27    /// PUT /user-keys
28    async fn put_user_key(&self, request_model: UserKeyKeyRequestModel) -> Result<(), Error>;
29}
30
31pub struct UserKeysApiClient {
32    configuration: Arc<Configuration>,
33}
34
35impl UserKeysApiClient {
36    pub fn new(configuration: Arc<Configuration>) -> Self {
37        Self { configuration }
38    }
39}
40
41#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
42#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
43impl UserKeysApi for UserKeysApiClient {
44    async fn get_user_key(&self) -> Result<UserKeyResponseModel, Error> {
45        let response = request(&self.configuration, Method::GET, None::<()>).await?;
46
47        let body = response.text().await?;
48        let response_model = serde_json::from_str::<UserKeyResponseModel>(&body)?;
49        Ok(response_model)
50    }
51
52    async fn post_user_key(&self, request_model: UserKeyKeyRequestModel) -> Result<(), Error> {
53        request(&self.configuration, Method::POST, Some(request_model)).await?;
54
55        Ok(())
56    }
57
58    async fn put_user_key(&self, request_model: UserKeyKeyRequestModel) -> Result<(), Error> {
59        request(&self.configuration, Method::PUT, Some(request_model)).await?;
60
61        Ok(())
62    }
63}
64
65async fn request(
66    configuration: &Arc<Configuration>,
67    method: Method,
68    body: Option<impl Serialize>,
69) -> Result<reqwest::Response, Error> {
70    let url = format!("{}/user-keys", configuration.base_path);
71
72    let mut request = configuration
73        .client
74        .request(method, url)
75        .header(reqwest::header::CONTENT_TYPE, "application/json")
76        .header(reqwest::header::ACCEPT, "application/json");
77
78    if let Some(ref user_agent) = configuration.user_agent {
79        request = request.header(reqwest::header::USER_AGENT, user_agent.clone());
80    }
81    if let Some(ref access_token) = configuration.oauth_access_token {
82        request = request.bearer_auth(access_token.clone());
83    }
84    request = request.with_extension(AuthRequired::Bearer);
85    if let Some(ref body) = body {
86        request =
87            request.body(serde_json::to_string(&body).expect("Serialize should be infallible"))
88    }
89
90    let response = request.send().await?;
91
92    Ok(response.error_for_status()?)
93}
94
95#[cfg(test)]
96mod tests {
97    use std::sync::Arc;
98
99    use bitwarden_api_base::Configuration;
100    use wiremock::{
101        Mock, MockServer, ResponseTemplate,
102        matchers::{header, method, path},
103    };
104
105    use crate::{
106        apis::user_keys_api::{UserKeysApi, UserKeysApiClient},
107        models::user_key_request_model::UserKeyKeyRequestModel,
108    };
109
110    const ACCESS_TOKEN: &str = "test_access_token";
111    const KEY_CONNECTOR_KEY: &str = "test_key_connector_key";
112
113    async fn setup_mock_server_with_auth() -> (MockServer, Configuration) {
114        let server = MockServer::start().await;
115
116        let configuration = Configuration {
117            base_path: format!("http://{}", server.address()),
118            user_agent: Some("Bitwarden Rust-SDK [TEST]".to_string()),
119            client: reqwest::Client::new().into(),
120            oauth_access_token: Some(ACCESS_TOKEN.to_string()),
121        };
122
123        (server, configuration)
124    }
125
126    #[tokio::test]
127    async fn test_get() {
128        let (server, configuration) = setup_mock_server_with_auth().await;
129
130        Mock::given(method("GET"))
131            .and(path("/user-keys"))
132            .and(header("authorization", format!("Bearer {ACCESS_TOKEN}")))
133            .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
134                "key": KEY_CONNECTOR_KEY.to_string()
135            })))
136            .expect(1)
137            .mount(&server)
138            .await;
139
140        let api_client = UserKeysApiClient::new(Arc::new(configuration));
141
142        let result = api_client.get_user_key().await;
143
144        assert!(result.is_ok());
145        assert_eq!(KEY_CONNECTOR_KEY, result.unwrap().key);
146    }
147
148    #[tokio::test]
149    async fn test_post() {
150        let (server, configuration) = setup_mock_server_with_auth().await;
151
152        Mock::given(method("POST"))
153            .and(path("/user-keys"))
154            .and(header("authorization", format!("Bearer {ACCESS_TOKEN}")))
155            .and(header("content-type", "application/json"))
156            .respond_with(ResponseTemplate::new(200))
157            .expect(1)
158            .mount(&server)
159            .await;
160
161        let request_model = UserKeyKeyRequestModel {
162            key: KEY_CONNECTOR_KEY.to_string(),
163        };
164
165        let api_client = UserKeysApiClient::new(Arc::new(configuration));
166
167        let result = api_client.post_user_key(request_model).await;
168
169        assert!(result.is_ok());
170    }
171
172    #[tokio::test]
173    async fn test_put() {
174        let (server, configuration) = setup_mock_server_with_auth().await;
175
176        Mock::given(method("PUT"))
177            .and(path("/user-keys"))
178            .and(header("authorization", format!("Bearer {ACCESS_TOKEN}")))
179            .and(header("content-type", "application/json"))
180            .respond_with(ResponseTemplate::new(200))
181            .expect(1)
182            .mount(&server)
183            .await;
184
185        let request_model = UserKeyKeyRequestModel {
186            key: KEY_CONNECTOR_KEY.to_string(),
187        };
188
189        let api_client = UserKeysApiClient::new(Arc::new(configuration));
190
191        let result = api_client.put_user_key(request_model).await;
192
193        assert!(result.is_ok());
194    }
195}