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