Skip to main content

bitwarden_pm/
lib.rs

1#![doc = include_str!("../README.md")]
2
3#[cfg(feature = "bitwarden-license")]
4mod commercial;
5
6use std::sync::Arc;
7
8use bitwarden_auth::AuthClientExt as _;
9use bitwarden_core::{
10    ClientBuilder, FromClient,
11    auth::{ClientManagedTokenHandler, ClientManagedTokens},
12    client::tracing_middleware::ReqwestTracingMiddleware,
13};
14use bitwarden_crypto_cipher_suite::CryptoCipherSuiteClientExt as _;
15#[cfg(not(target_arch = "wasm32"))]
16use bitwarden_crypto_sync_handler::CryptoSyncHandler;
17use bitwarden_crypto_sync_handler::CryptoSyncHandlerClientExt as _;
18use bitwarden_exporters::ExporterClientExt as _;
19use bitwarden_generators::GeneratorClientsExt as _;
20use bitwarden_importers::ImporterClientExt as _;
21use bitwarden_managed_settings::{ManagedSettingsClient, ManagedSettingsClientExt as _};
22use bitwarden_organization_invite_link::InviteLinkClientExt as _;
23use bitwarden_policies::PoliciesClientExt as _;
24use bitwarden_send::{SendClientExt as _, SendSyncHandler, SendSyncHandlerClientExt as _};
25use bitwarden_sync::SyncClientExt as _;
26use bitwarden_unlock::UnlockClientExt as _;
27use bitwarden_user_crypto_management::UserCryptoManagementClientExt;
28use bitwarden_vault::{FolderSyncHandler, VaultClientExt as _};
29
30#[cfg(feature = "uniffi")]
31uniffi::setup_scaffolding!();
32
33/// Re-export subclients for easier access
34pub mod clients {
35    pub use bitwarden_auth::AuthClient;
36    pub use bitwarden_collections::collection_client::CollectionsClient;
37    pub use bitwarden_core::key_management::CryptoClient;
38    pub use bitwarden_crypto_cipher_suite::CryptoCipherSuiteClient;
39    pub use bitwarden_crypto_sync_handler::CryptoSyncHandlerClient;
40    pub use bitwarden_exporters::ExporterClient;
41    pub use bitwarden_generators::GeneratorClient;
42    pub use bitwarden_importers::ImporterClient;
43    pub use bitwarden_organization_invite_link::InviteLinkClient;
44    pub use bitwarden_policies::PolicyClient;
45    pub use bitwarden_send::{SendClient, SendSyncHandlerClient};
46    pub use bitwarden_sync::SyncClient;
47    pub use bitwarden_unlock::UnlockClient;
48    pub use bitwarden_vault::VaultClient;
49}
50#[cfg(feature = "bitwarden-license")]
51pub use commercial::CommercialPasswordManagerClient;
52
53mod builder;
54pub mod migrations;
55pub use bitwarden_core::{RehydrationError, SaveStateData};
56pub use bitwarden_unlock::{SessionKey, UnlockError, UnlockMethod};
57pub use builder::PasswordManagerClientBuilder;
58
59/// The main entry point for the Bitwarden Password Manager SDK
60pub struct PasswordManagerClient(pub bitwarden_core::Client);
61
62impl PasswordManagerClient {
63    /// Initialize a new instance of the SDK client
64    pub fn new(settings: Option<bitwarden_core::ClientSettings>) -> Self {
65        let mut builder = PasswordManagerClientBuilder::new();
66        if let Some(s) = settings {
67            builder = builder.with_settings(s);
68        }
69        builder.build()
70    }
71
72    /// Returns a [`PasswordManagerClientBuilder`] for constructing a new [`PasswordManagerClient`].
73    pub fn builder() -> PasswordManagerClientBuilder {
74        PasswordManagerClientBuilder::new()
75    }
76
77    /// Initialize a new instance of the SDK client with client-managed tokens and a shared
78    /// managed-settings handle.
79    ///
80    /// `managed_settings` is owned by the host application, which acquires a management profile
81    /// from the operating system's device-management channel and pushes it in. Only its cell is
82    /// captured, so profiles the host pushes later are visible to this client.
83    pub fn new_with_client_tokens(
84        settings: Option<bitwarden_core::ClientSettings>,
85        tokens: Arc<dyn ClientManagedTokens>,
86        managed_settings: &ManagedSettingsClient,
87    ) -> Self {
88        let mut builder = ClientBuilder::new()
89            .with_token_handler(ClientManagedTokenHandler::new(tokens))
90            .with_middleware(vec![Arc::new(ReqwestTracingMiddleware)])
91            .with_managed_profile(managed_settings.cell());
92        if let Some(s) = settings {
93            builder = builder.with_settings(s);
94        }
95        Self(builder.build())
96    }
97
98    /// Initialize a new instance of the SDK client with SDK managed state and sync handlers
99    /// registered
100    ///
101    /// This will eventually replace `new` when the SDK fully owns sync on all clients.
102    pub fn new_with_sync(settings: Option<bitwarden_core::ClientSettings>) -> Self {
103        let client = Self::new(settings);
104
105        let sync = client.sync();
106        #[cfg(not(target_arch = "wasm32"))]
107        sync.register_sync_handler(Arc::new(CryptoSyncHandler::new(client.0.clone())));
108        sync.register_sync_handler(Arc::new(FolderSyncHandler::from_client(&client.0)));
109        sync.register_sync_handler(Arc::new(SendSyncHandler::from_client(&client.0)));
110
111        // TODO: Add more sync handlers here!
112
113        client
114    }
115
116    /// Platform operations
117    pub fn platform(&self) -> bitwarden_core::platform::PlatformClient {
118        self.0.platform()
119    }
120
121    /// Administrator-enforced settings operations.
122    pub fn managed_settings(&self) -> ManagedSettingsClient {
123        self.0.managed_settings()
124    }
125
126    /// Auth operations
127    pub fn auth(&self) -> bitwarden_auth::AuthClient {
128        self.0.auth_new()
129    }
130
131    /// Bitwarden licensed operations
132    #[cfg(feature = "bitwarden-license")]
133    pub fn commercial(&self) -> CommercialPasswordManagerClient {
134        CommercialPasswordManagerClient::new(self.0.clone())
135    }
136
137    /// Crypto operations
138    pub fn crypto(&self) -> bitwarden_core::key_management::CryptoClient {
139        self.0.crypto()
140    }
141
142    /// Crypto cipher suite operations
143    pub fn crypto_cipher_suite(&self) -> bitwarden_crypto_cipher_suite::CryptoCipherSuiteClient {
144        self.0.crypto_cipher_suite()
145    }
146
147    /// Feature flag operations
148    pub fn flags(&self) -> bitwarden_core::FlagsClient {
149        self.0.flags()
150    }
151
152    /// Key management operations that run on every sync
153    pub fn crypto_sync_handler(&self) -> bitwarden_crypto_sync_handler::CryptoSyncHandlerClient {
154        self.0.crypto_sync_handler()
155    }
156
157    /// Operations that manage the cryptographic machinery of a user account, including key-rotation
158    pub fn user_crypto_management(
159        &self,
160    ) -> bitwarden_user_crypto_management::UserCryptoManagementClient {
161        self.0.user_crypto_management()
162    }
163
164    /// Vault item operations
165    pub fn vault(&self) -> bitwarden_vault::VaultClient {
166        self.0.vault()
167    }
168
169    /// Collection related operations.
170    ///
171    /// This is registered directly on the top-level client in addition to being nested under
172    /// [`vault`](Self::vault); once all consumers have migrated to this accessor, the nested one
173    /// will be removed.
174    pub fn collections(&self) -> bitwarden_collections::collection_client::CollectionsClient {
175        bitwarden_collections::collection_client::CollectionsClient::from_client(&self.0)
176    }
177
178    /// Exporter operations
179    pub fn exporters(&self) -> bitwarden_exporters::ExporterClient {
180        self.0.exporters()
181    }
182
183    /// Importer operations
184    pub fn importers(&self) -> bitwarden_importers::ImporterClient {
185        self.0.importers()
186    }
187
188    /// Generator operations
189    pub fn generator(&self) -> bitwarden_generators::GeneratorClient {
190        self.0.generator()
191    }
192
193    /// Send operations
194    pub fn sends(&self) -> bitwarden_send::SendClient {
195        self.0.sends()
196    }
197
198    /// Send sync handler operations
199    pub fn send_sync_handler(&self) -> bitwarden_send::SendSyncHandlerClient {
200        self.0.send_sync_handler()
201    }
202
203    /// Policy operations
204    pub fn policies(&self) -> bitwarden_policies::PolicyClient {
205        self.0.policies()
206    }
207
208    /// Organization invite link operations
209    pub fn invite_link(&self) -> bitwarden_organization_invite_link::InviteLinkClient {
210        self.0.invite_link()
211    }
212
213    /// Sync operations
214    pub fn sync(&self) -> bitwarden_sync::SyncClient {
215        self.0.sync()
216    }
217
218    /// Returns true when the user's symmetric key is loaded into the key store.
219    pub fn is_unlocked(&self) -> bool {
220        use bitwarden_core::key_management::SymmetricKeySlotId;
221        self.0
222            .internal
223            .get_key_store()
224            .context()
225            .has_symmetric_key(SymmetricKeySlotId::User)
226    }
227
228    /// Unlock operations
229    pub fn unlock(&self) -> bitwarden_unlock::UnlockClient {
230        self.0.unlock()
231    }
232
233    /// Write rehydration state to a StateRegistry.
234    ///
235    /// Delegates to [`Client::save_to_state`](bitwarden_core::Client::save_to_state).
236    pub async fn save_to_state(
237        data: SaveStateData,
238        reg: &bitwarden_state::registry::StateRegistry,
239    ) -> Result<(), RehydrationError> {
240        bitwarden_core::Client::save_to_state(data, reg).await
241    }
242
243    /// Reconstruct a locked PasswordManagerClient from a populated StateRegistry.
244    ///
245    /// Delegates to [`Client::load_from_state`](bitwarden_core::Client::load_from_state).
246    pub async fn load_from_state(
247        token_handler: std::sync::Arc<dyn bitwarden_core::auth::auth_tokens::TokenHandler>,
248        registry: bitwarden_state::registry::StateRegistry,
249    ) -> Result<Self, RehydrationError> {
250        let client = bitwarden_core::Client::load_from_state(token_handler, registry).await?;
251        Ok(PasswordManagerClient(client))
252    }
253}
254
255#[cfg(test)]
256mod tests {
257    use std::sync::Arc;
258
259    use super::*;
260
261    #[test]
262    fn new_with_server_communication_config_constructs() {
263        struct MockCookieProvider;
264
265        #[async_trait::async_trait]
266        impl bitwarden_server_communication_config::CookieProvider for MockCookieProvider {
267            async fn cookies(&self, _hostname: &str) -> Vec<(String, String)> {
268                vec![]
269            }
270
271            async fn acquire_cookie(
272                &self,
273                _hostname: &str,
274            ) -> Result<(), bitwarden_server_communication_config::AcquireCookieError> {
275                Ok(())
276            }
277
278            async fn needs_bootstrap(&self, _hostname: &str) -> bool {
279                false
280            }
281        }
282
283        let _client = PasswordManagerClient::builder()
284            .with_server_communication_config(Arc::new(MockCookieProvider))
285            .build();
286    }
287}