bitwarden_vault/cipher/cipher_client/
get.rs

1use bitwarden_core::key_management::KeyIds;
2use bitwarden_crypto::{CryptoError, KeyStore};
3use bitwarden_error::bitwarden_error;
4use bitwarden_state::repository::{Repository, RepositoryError};
5use thiserror::Error;
6#[cfg(feature = "wasm")]
7use wasm_bindgen::prelude::wasm_bindgen;
8
9use super::CiphersClient;
10use crate::{Cipher, CipherView, ItemNotFoundError, cipher::cipher::DecryptCipherListResult};
11
12#[allow(missing_docs)]
13#[bitwarden_error(flat)]
14#[derive(Debug, Error)]
15pub enum GetCipherError {
16    #[error(transparent)]
17    ItemNotFound(#[from] ItemNotFoundError),
18    #[error(transparent)]
19    Crypto(#[from] CryptoError),
20    #[error(transparent)]
21    Repository(#[from] RepositoryError),
22}
23
24async fn get_cipher(
25    store: &KeyStore<KeyIds>,
26    repository: &dyn Repository<Cipher>,
27    id: &str,
28) -> Result<CipherView, GetCipherError> {
29    let cipher = repository
30        .get(id.to_string())
31        .await?
32        .ok_or(ItemNotFoundError)?;
33
34    Ok(store.decrypt(&cipher)?)
35}
36
37async fn list_ciphers(
38    store: &KeyStore<KeyIds>,
39    repository: &dyn Repository<Cipher>,
40) -> Result<DecryptCipherListResult, GetCipherError> {
41    let ciphers = repository.list().await?;
42    let (successes, failures) = store.decrypt_list_with_failures(&ciphers);
43    Ok(DecryptCipherListResult {
44        successes,
45        failures: failures.into_iter().cloned().collect(),
46    })
47}
48
49#[cfg_attr(feature = "wasm", wasm_bindgen)]
50impl CiphersClient {
51    /// Get all ciphers from state and decrypt them, returning both successes and failures.
52    /// This method will not fail when some ciphers fail to decrypt, allowing for graceful
53    /// handling of corrupted or problematic cipher data.
54    pub async fn list(&self) -> Result<DecryptCipherListResult, GetCipherError> {
55        let key_store = self.client.internal.get_key_store();
56        let repository = self.get_repository()?;
57
58        list_ciphers(key_store, repository.as_ref()).await
59    }
60
61    /// Get [Cipher] by ID from state and decrypt it to a [CipherView].
62    pub async fn get(&self, cipher_id: &str) -> Result<CipherView, GetCipherError> {
63        let key_store = self.client.internal.get_key_store();
64        let repository = self.get_repository()?;
65
66        get_cipher(key_store, repository.as_ref(), cipher_id).await
67    }
68}