Skip to main content

bitwarden_vault/cipher/attachment_client/
mod.rs

1use std::{path::Path, sync::Arc};
2
3use bitwarden_core::{FromClient, client::ApiConfigurations, key_management::KeySlotIds};
4use bitwarden_crypto::{EncString, KeyStore};
5use bitwarden_error::bitwarden_error;
6use bitwarden_state::repository::Repository;
7use thiserror::Error;
8
9use crate::{
10    Attachment, AttachmentEncryptResult, AttachmentFile, AttachmentFileView, AttachmentView,
11    Cipher, DecryptError, EncryptError,
12};
13
14mod admin;
15mod create;
16mod delete;
17mod download_url;
18mod renew;
19mod upgrade;
20
21pub use admin::{
22    AttachmentAdminClient, CipherAdminGetAttachmentDownloadUrlError, CreateAttachmentAdminError,
23    DeleteAttachmentAdminError,
24};
25pub use create::{
26    AttachmentFileUploadType, CipherCreateAttachmentError, CreateAttachmentRequest,
27    CreatedAttachment,
28};
29pub use delete::CipherDeleteAttachmentError;
30pub use download_url::CipherGetAttachmentDownloadUrlError;
31pub use renew::CipherRenewFileUploadUrlError;
32pub use upgrade::CipherUpgradeAttachmentError;
33
34/// Generic error type for vault encryption errors.
35#[allow(missing_docs)]
36#[bitwarden_error(flat)]
37#[derive(Debug, Error)]
38pub enum EncryptFileError {
39    #[error(transparent)]
40    Encrypt(#[from] EncryptError),
41    #[error(transparent)]
42    Io(#[from] std::io::Error),
43}
44
45/// Generic error type for decryption errors
46#[allow(missing_docs)]
47#[bitwarden_error(flat)]
48#[derive(Debug, Error)]
49pub enum DecryptFileError {
50    #[error(transparent)]
51    Decrypt(#[from] DecryptError),
52    #[error(transparent)]
53    Io(#[from] std::io::Error),
54}
55
56/// Wrapper for attachment-specific cipher operations.
57#[bitwarden_ffi::wasm_object]
58#[derive(FromClient)]
59pub struct AttachmentsClient {
60    pub(crate) key_store: KeyStore<KeySlotIds>,
61    pub(crate) api_configurations: Arc<ApiConfigurations>,
62    pub(crate) repository: Option<Arc<dyn Repository<Cipher>>>,
63    pub(crate) http_client: reqwest::Client,
64}
65
66#[bitwarden_ffi::wasm_export]
67impl AttachmentsClient {
68    /// Returns a new client for performing attachment admin operations.
69    /// Uses the admin server API endpoints and does not modify local state.
70    pub fn admin(&self) -> AttachmentAdminClient {
71        AttachmentAdminClient {
72            api_configurations: self.api_configurations.clone(),
73        }
74    }
75
76    #[allow(missing_docs)]
77    pub fn decrypt_buffer(
78        &self,
79        cipher: Cipher,
80        attachment: AttachmentView,
81        encrypted_buffer: &[u8],
82    ) -> Result<Vec<u8>, DecryptError> {
83        Ok(self.key_store.decrypt(&AttachmentFile {
84            cipher,
85            attachment,
86            contents: EncString::from_buffer(encrypted_buffer)?,
87        })?)
88    }
89}
90
91impl AttachmentsClient {
92    #[allow(missing_docs)]
93    pub fn encrypt_buffer(
94        &self,
95        cipher: Cipher,
96        attachment: AttachmentView,
97        buffer: &[u8],
98    ) -> Result<AttachmentEncryptResult, EncryptError> {
99        Ok(self.key_store.encrypt(AttachmentFileView {
100            cipher,
101            attachment,
102            contents: buffer,
103        })?)
104    }
105
106    #[allow(missing_docs)]
107    pub fn encrypt_file(
108        &self,
109        cipher: Cipher,
110        attachment: AttachmentView,
111        decrypted_file_path: &Path,
112        encrypted_file_path: &Path,
113    ) -> Result<Attachment, EncryptFileError> {
114        let data = std::fs::read(decrypted_file_path)?;
115        let AttachmentEncryptResult {
116            attachment,
117            contents,
118        } = self.encrypt_buffer(cipher, attachment, &data)?;
119        std::fs::write(encrypted_file_path, contents)?;
120        Ok(attachment)
121    }
122
123    #[allow(missing_docs)]
124    pub fn decrypt_file(
125        &self,
126        cipher: Cipher,
127        attachment: AttachmentView,
128        encrypted_file_path: &Path,
129        decrypted_file_path: &Path,
130    ) -> Result<(), DecryptFileError> {
131        let data = std::fs::read(encrypted_file_path)?;
132        let decrypted = self.decrypt_buffer(cipher, attachment, &data)?;
133        std::fs::write(decrypted_file_path, decrypted)?;
134        Ok(())
135    }
136}