diff --git a/crates/bitwarden-exporters/src/client_exporter.rs b/crates/bitwarden-exporters/src/client_exporter.rs index 5f7bca39..c5fd645a 100644 --- a/crates/bitwarden-exporters/src/client_exporter.rs +++ b/crates/bitwarden-exporters/src/client_exporter.rs @@ -3,7 +3,7 @@ use bitwarden_vault::{Cipher, Collection, Folder}; use crate::{ export::{export_cxf, export_organization_vault, export_vault}, - ExportError, ExportFormat, + Account, ExportError, ExportFormat, }; pub struct ClientExporters<'a> { @@ -33,8 +33,12 @@ impl<'a> ClientExporters<'a> { export_organization_vault(collections, ciphers, format) } - pub fn export_cxf(&self, ciphers: Vec) -> Result { - export_cxf(self.client, ciphers) + pub fn export_cxf( + &self, + account: Account, + ciphers: Vec, + ) -> Result { + export_cxf(self.client, account, ciphers) } } diff --git a/crates/bitwarden-exporters/src/cxp/mod.rs b/crates/bitwarden-exporters/src/cxp/mod.rs index ffb1f03c..70d0407e 100644 --- a/crates/bitwarden-exporters/src/cxp/mod.rs +++ b/crates/bitwarden-exporters/src/cxp/mod.rs @@ -2,32 +2,42 @@ use bitwarden_crypto::generate_random_bytes; use chrono::Utc; use credential_exchange_types::{ format::{ - Account, BasicAuthCredential, Credential, EditableField, FieldType, Header, Item, ItemType, + Account as CxpAccount, BasicAuthCredential, Credential, EditableField, FieldType, Header, + Item, ItemType, }, B64Url, }; +use uuid::Uuid; use crate::{Cipher, CipherType, Login}; mod error; pub use error::CxpError; -pub(crate) fn build_cxf(ciphers: Vec) -> Result { +#[derive(Debug)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct Account { + id: Uuid, + email: String, + name: Option, +} + +pub(crate) fn build_cxf(account: Account, ciphers: Vec) -> Result { let items: Vec = ciphers.into_iter().map(|cipher| cipher.into()).collect(); let header = Header { version: 0, exporter: "Bitwarden".to_string(), timestamp: Utc::now().timestamp() as u64, - accounts: vec![Account { - id: todo!(), - user_name: todo!(), - email: todo!(), - full_name: todo!(), - icon: todo!(), - collections: todo!(), + accounts: vec![CxpAccount { + id: account.id.as_bytes().as_slice().into(), + user_name: "".to_owned(), + email: account.email, + full_name: account.name, + icon: None, + collections: vec![], items, - extensions: todo!(), + extensions: None, }], }; diff --git a/crates/bitwarden-exporters/src/export.rs b/crates/bitwarden-exporters/src/export.rs index 5eb181c8..40e31922 100644 --- a/crates/bitwarden-exporters/src/export.rs +++ b/crates/bitwarden-exporters/src/export.rs @@ -3,7 +3,10 @@ use bitwarden_crypto::KeyDecryptable; use bitwarden_vault::{Cipher, CipherView, Collection, Folder, FolderView}; use crate::{ - csv::export_csv, cxp::build_cxf, encrypted_json::export_encrypted_json, json::export_json, + csv::export_csv, + cxp::{build_cxf, Account}, + encrypted_json::export_encrypted_json, + json::export_json, ExportError, ExportFormat, }; @@ -42,12 +45,16 @@ pub(crate) fn export_organization_vault( todo!(); } -pub(crate) fn export_cxf(client: &Client, ciphers: Vec) -> Result { +pub(crate) fn export_cxf( + client: &Client, + account: Account, + ciphers: Vec, +) -> Result { let enc = client.internal.get_encryption_settings()?; let key = enc.get_key(&None)?; let ciphers: Vec = ciphers.decrypt_with_key(key)?; let ciphers: Vec = ciphers.into_iter().flat_map(|c| c.try_into()).collect(); - Ok(build_cxf(ciphers)?) + Ok(build_cxf(account, ciphers)?) } diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index b9d687b1..c22b49b0 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -6,10 +6,13 @@ use uuid::Uuid; #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); +#[cfg(feature = "uniffi")] +mod uniffi_support; mod client_exporter; mod csv; mod cxp; +pub use cxp::Account; mod encrypted_json; mod json; mod models; diff --git a/crates/bitwarden-exporters/src/uniffi_support.rs b/crates/bitwarden-exporters/src/uniffi_support.rs new file mode 100644 index 00000000..5bf94d09 --- /dev/null +++ b/crates/bitwarden-exporters/src/uniffi_support.rs @@ -0,0 +1,3 @@ +use uuid::Uuid; + +uniffi::ffi_converter_forward!(Uuid, bitwarden_core::UniFfiTag, crate::UniFfiTag); diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index dbef90f8..31356821 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bitwarden_exporters::{ClientExportersExt, ExportFormat}; +use bitwarden_exporters::{Account, ClientExportersExt, ExportFormat}; use bitwarden_generators::{ ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, @@ -91,12 +91,12 @@ impl ClientExporters { /// /// For use with Apple using [ASCredentialExportManager](https://developer.apple.com/documentation/authenticationservices/ascredentialexportmanager). /// Ideally the output should be immediately deserialized to [ASExportedCredentialData](https://developer.apple.com/documentation/authenticationservices/asexportedcredentialdata). - pub fn export_cxf(&self, ciphers: Vec) -> Result { + pub fn export_cxf(&self, account: Account, ciphers: Vec) -> Result { Ok(self .0 .0 .exporters() - .export_cxf(ciphers) + .export_cxf(account, ciphers) .map_err(Error::ExportError)?) } }