Skip to main content

bitwarden_importers/
importer_client.rs

1use bitwarden_core::Client;
2#[cfg(feature = "wasm")]
3use wasm_bindgen::prelude::*;
4
5use crate::{
6    Credentials, ImportError, ImportOptions, ImportSummary, OnePasswordImportSummary,
7    OnePasswordSignInMethods, OnePasswordTwoFactorUi, SignInAddress,
8    import::{import_kdbx, import_onepassword, onepassword_sign_in_methods},
9};
10
11#[allow(missing_docs)]
12#[cfg_attr(feature = "wasm", wasm_bindgen)]
13pub struct ImporterClient {
14    client: Client,
15}
16
17#[cfg_attr(feature = "wasm", wasm_bindgen)]
18impl ImporterClient {
19    fn new(client: Client) -> Self {
20        Self { client }
21    }
22
23    /// Import a KeePass KDBX (`.kdbx`) database and submit it to the server.
24    ///
25    /// Parses and decrypts the raw `.kdbx` bytes (unlocked with the password and/or key file),
26    /// encrypts the entries for the user's personal vault or the given organization, and submits
27    /// them to the import endpoint. Returns the counts of what was imported. Inputs larger than
28    /// 10 MiB are rejected with `KdbxFileTooLarge`.
29    pub async fn import_kdbx(
30        &self,
31        file: Vec<u8>,
32        password: Option<String>,
33        key_file: Option<Vec<u8>>,
34        options: ImportOptions,
35    ) -> Result<ImportSummary, ImportError> {
36        import_kdbx(&self.client, file, password, key_file, options).await
37    }
38
39    /// Asks 1Password how the account signs in: with the password and Secret Key, with SSO, or
40    /// either. It needs only the email and the sign-in address, so the UI can call it before asking
41    /// for the password and Secret Key. Fails with [`ImportError::OnePasswordInvalidEmail`] when
42    /// 1Password refuses the email as malformed.
43    pub async fn onepassword_sign_in_methods(
44        &self,
45        username: String,
46        sign_in_address: SignInAddress,
47    ) -> Result<OnePasswordSignInMethods, ImportError> {
48        onepassword_sign_in_methods(&self.client, username, sign_in_address).await
49    }
50}
51
52#[cfg(feature = "wasm")]
53#[wasm_bindgen]
54impl ImporterClient {
55    /// The same import as [`ImporterClient::import_onepassword`], for JavaScript, which passes the
56    /// two-factor prompt as an object rather than a `&dyn` callback.
57    #[wasm_bindgen(js_name = import_onepassword)]
58    pub async fn import_onepassword_wasm(
59        &self,
60        credentials: Credentials,
61        two_factor: crate::wasm::RawJsOnePasswordTwoFactorUi,
62        options: ImportOptions,
63    ) -> Result<OnePasswordImportSummary, ImportError> {
64        let two_factor = crate::wasm::JsOnePasswordTwoFactorUi::new(two_factor);
65        import_onepassword(&self.client, credentials, &two_factor, options).await
66    }
67}
68
69// Separate from the block above: `wasm_bindgen` cannot export the `&dyn` two-factor callback.
70impl ImporterClient {
71    /// Import a 1Password account directly from the 1Password servers.
72    ///
73    /// Signs in with the email, master password and Secret Key in `credentials`, asking
74    /// `two_factor` for a code when the account requires one, downloads and decrypts every vault
75    /// the account can open, and submits the result to the import endpoint. Each vault becomes a
76    /// folder. Returns the imported counts plus any vaults or items that could not be imported.
77    pub async fn import_onepassword(
78        &self,
79        credentials: Credentials,
80        two_factor: &dyn OnePasswordTwoFactorUi,
81        options: ImportOptions,
82    ) -> Result<OnePasswordImportSummary, ImportError> {
83        import_onepassword(&self.client, credentials, two_factor, options).await
84    }
85}
86
87#[allow(missing_docs)]
88pub trait ImporterClientExt {
89    fn importers(&self) -> ImporterClient;
90}
91
92impl ImporterClientExt for Client {
93    fn importers(&self) -> ImporterClient {
94        ImporterClient::new(self.clone())
95    }
96}