bitwarden_sm/secrets/
sync.rs

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