Skip to main content

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::{
11    Cipher, CipherView, ItemNotFoundError,
12    cipher::cipher::{DecryptCipherListResult, DecryptCipherResult},
13};
14
15#[allow(missing_docs)]
16#[bitwarden_error(flat)]
17#[derive(Debug, Error)]
18pub enum GetCipherError {
19    #[error(transparent)]
20    ItemNotFound(#[from] ItemNotFoundError),
21    #[error(transparent)]
22    Crypto(#[from] CryptoError),
23    #[error(transparent)]
24    Repository(#[from] RepositoryError),
25}
26
27async fn get_cipher(
28    store: &KeyStore<KeyIds>,
29    repository: &dyn Repository<Cipher>,
30    id: &str,
31) -> Result<CipherView, GetCipherError> {
32    let id = id.parse().map_err(|_| ItemNotFoundError)?;
33    let cipher = repository.get(id).await?.ok_or(ItemNotFoundError)?;
34
35    Ok(store.decrypt(&cipher)?)
36}
37
38async fn list_ciphers(
39    store: &KeyStore<KeyIds>,
40    repository: &dyn Repository<Cipher>,
41) -> Result<DecryptCipherListResult, GetCipherError> {
42    let ciphers = repository.list().await?;
43    let (successes, failures) = store.decrypt_list_with_failures(&ciphers);
44    Ok(DecryptCipherListResult {
45        successes,
46        failures: failures.into_iter().cloned().collect(),
47    })
48}
49
50async fn get_all_ciphers(
51    store: &KeyStore<KeyIds>,
52    repository: &dyn Repository<Cipher>,
53) -> Result<DecryptCipherResult, GetCipherError> {
54    let ciphers = repository.list().await?;
55    let (successes, failures) = store.decrypt_list_with_failures(&ciphers);
56    Ok(DecryptCipherResult {
57        successes,
58        failures: failures.into_iter().cloned().collect(),
59    })
60}
61
62#[cfg_attr(feature = "wasm", wasm_bindgen)]
63impl CiphersClient {
64    /// Get all ciphers from state and decrypt them to [crate::CipherListView], returning both
65    /// successes and failures. This method will not fail when some ciphers fail to decrypt,
66    /// allowing for graceful handling of corrupted or problematic cipher data.
67    pub async fn list(&self) -> Result<DecryptCipherListResult, GetCipherError> {
68        let key_store = self.client.internal.get_key_store();
69        let repository = self.get_repository()?;
70
71        list_ciphers(key_store, repository.as_ref()).await
72    }
73
74    /// Get all ciphers from state and decrypt them to full [CipherView], returning both
75    /// successes and failures. This method will not fail when some ciphers fail to decrypt,
76    /// allowing for graceful handling of corrupted or problematic cipher data.
77    pub async fn get_all(&self) -> Result<DecryptCipherResult, GetCipherError> {
78        let key_store = self.client.internal.get_key_store();
79        let repository = self.get_repository()?;
80
81        get_all_ciphers(key_store, repository.as_ref()).await
82    }
83
84    /// Get [Cipher] by ID from state and decrypt it to a [CipherView].
85    pub async fn get(&self, cipher_id: &str) -> Result<CipherView, GetCipherError> {
86        let key_store = self.client.internal.get_key_store();
87        let repository = self.get_repository()?;
88
89        get_cipher(key_store, repository.as_ref(), cipher_id).await
90    }
91}