Skip to main content

bitwarden_pm/
lib.rs

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