Skip to main content

bitwarden_sm/secrets/
sync.rs

1use bitwarden_api_api::models::SecretsSyncResponseModel;
2use bitwarden_core::{key_management::KeyIds, require};
3use bitwarden_crypto::KeyStoreContext;
4use chrono::{DateTime, Utc};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::{SecretsManagerClient, error::SecretsManagerError, secrets::SecretResponse};
10
11#[allow(missing_docs)]
12#[derive(Serialize, Deserialize, Debug, JsonSchema)]
13#[serde(rename_all = "camelCase", deny_unknown_fields)]
14pub struct SecretsSyncRequest {
15    /// Organization to sync secrets from
16    pub organization_id: Uuid,
17    /// Optional date time a sync last occurred
18    pub last_synced_date: Option<DateTime<Utc>>,
19}
20
21pub(crate) async fn sync_secrets(
22    client: &SecretsManagerClient,
23    input: &SecretsSyncRequest,
24) -> Result<SecretsSyncResponse, SecretsManagerError> {
25    let client = client.client();
26    let config = client.internal.get_api_configurations();
27    let last_synced_date = input.last_synced_date.map(|date| date.to_rfc3339());
28
29    let res = config
30        .api_client
31        .secrets_api()
32        .get_secrets_sync(input.organization_id, last_synced_date)
33        .await?;
34
35    let key_store = client.internal.get_key_store();
36
37    SecretsSyncResponse::process_response(res, &mut key_store.context())
38}
39
40#[allow(missing_docs)]
41#[derive(Serialize, Deserialize, Debug, JsonSchema)]
42#[serde(rename_all = "camelCase", deny_unknown_fields)]
43pub struct SecretsSyncResponse {
44    pub has_changes: bool,
45    pub secrets: Option<Vec<SecretResponse>>,
46}
47
48impl SecretsSyncResponse {
49    pub(crate) fn process_response(
50        response: SecretsSyncResponseModel,
51        ctx: &mut KeyStoreContext<KeyIds>,
52    ) -> Result<SecretsSyncResponse, SecretsManagerError> {
53        let has_changes = require!(response.has_changes);
54
55        if has_changes {
56            let secrets = require!(response.secrets)
57                .data
58                .unwrap_or_default()
59                .into_iter()
60                .map(|r| SecretResponse::process_base_response(r, ctx))
61                .collect::<Result<_, _>>()?;
62            return Ok(SecretsSyncResponse {
63                has_changes,
64                secrets: Some(secrets),
65            });
66        }
67
68        Ok(SecretsSyncResponse {
69            has_changes: false,
70            secrets: None,
71        })
72    }
73}