Skip to content

Commit 666ac41

Browse files
committed
Wip json export for Apple
1 parent 31323f5 commit 666ac41

File tree

6 files changed

+69
-5
lines changed

6 files changed

+69
-5
lines changed

crates/bitwarden-exporters/src/client_exporter.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bitwarden_core::Client;
22
use bitwarden_vault::{Cipher, Collection, Folder};
33

44
use crate::{
5-
export::{export_organization_vault, export_vault},
5+
export::{export_cxf, export_organization_vault, export_vault},
66
ExportError, ExportFormat,
77
};
88

@@ -32,6 +32,10 @@ impl<'a> ClientExporters<'a> {
3232
) -> Result<String, ExportError> {
3333
export_organization_vault(collections, ciphers, format)
3434
}
35+
36+
pub fn export_cxf(&self, ciphers: Vec<Cipher>) -> Result<String, ExportError> {
37+
export_cxf(self.client, ciphers)
38+
}
3539
}
3640

3741
pub trait ClientExportersExt<'a> {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use thiserror::Error;
2+
3+
#[derive(Error, Debug)]
4+
pub enum CxpError {
5+
#[error("JSON error: {0}")]
6+
Serde(#[from] serde_json::Error),
7+
}

crates/bitwarden-exporters/src/cxp.rs renamed to crates/bitwarden-exporters/src/cxp/mod.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,38 @@
11
use bitwarden_crypto::generate_random_bytes;
2+
use chrono::Utc;
23
use credential_exchange_types::{
3-
format::{BasicAuthCredential, Credential, EditableField, FieldType, Item, ItemType},
4+
format::{
5+
Account, BasicAuthCredential, Credential, EditableField, FieldType, Header, Item, ItemType,
6+
},
47
B64Url,
58
};
69

7-
use crate::{Cipher, CipherType, Login, LoginUri};
10+
use crate::{Cipher, CipherType, Login};
11+
12+
mod error;
13+
pub use error::CxpError;
14+
15+
pub(crate) fn build_cxf(ciphers: Vec<Cipher>) -> Result<String, CxpError> {
16+
let items: Vec<Item> = ciphers.into_iter().map(|cipher| cipher.into()).collect();
17+
18+
let header = Header {
19+
version: 0,
20+
exporter: "Bitwarden".to_string(),
21+
timestamp: Utc::now().timestamp() as u64,
22+
accounts: vec![Account {
23+
id: todo!(),
24+
user_name: todo!(),
25+
email: todo!(),
26+
full_name: todo!(),
27+
icon: todo!(),
28+
collections: todo!(),
29+
items,
30+
extensions: todo!(),
31+
}],
32+
};
33+
34+
Ok(serde_json::to_string(&header)?)
35+
}
836

937
impl From<Cipher> for Item {
1038
fn from(value: Cipher) -> Self {

crates/bitwarden-exporters/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pub enum ExportError {
99

1010
#[error("CSV error: {0}")]
1111
Csv(#[from] crate::csv::CsvError),
12+
#[error("Credential Exchange error: {0}")]
13+
CxpError(#[from] crate::cxp::CxpError),
1214
#[error("JSON error: {0}")]
1315
Json(#[from] crate::json::JsonError),
1416
#[error("Encrypted JSON error: {0}")]

crates/bitwarden-exporters/src/export.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use bitwarden_crypto::KeyDecryptable;
33
use bitwarden_vault::{Cipher, CipherView, Collection, Folder, FolderView};
44

55
use crate::{
6-
csv::export_csv, encrypted_json::export_encrypted_json, json::export_json, ExportError,
7-
ExportFormat,
6+
csv::export_csv, cxp::build_cxf, encrypted_json::export_encrypted_json, json::export_json,
7+
ExportError, ExportFormat,
88
};
99

1010
pub(crate) fn export_vault(
@@ -41,3 +41,13 @@ pub(crate) fn export_organization_vault(
4141
) -> Result<String, ExportError> {
4242
todo!();
4343
}
44+
45+
pub(crate) fn export_cxf(client: &Client, ciphers: Vec<Cipher>) -> Result<String, ExportError> {
46+
let enc = client.internal.get_encryption_settings()?;
47+
let key = enc.get_key(&None)?;
48+
49+
let ciphers: Vec<CipherView> = ciphers.decrypt_with_key(key)?;
50+
let ciphers: Vec<crate::Cipher> = ciphers.into_iter().flat_map(|c| c.try_into()).collect();
51+
52+
Ok(build_cxf(ciphers)?)
53+
}

crates/bitwarden-uniffi/src/tool/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,17 @@ impl ClientExporters {
8686
.export_organization_vault(collections, ciphers, format)
8787
.map_err(Error::ExportError)?)
8888
}
89+
90+
/// Credential Exchange Format (CXF)
91+
///
92+
/// For use with Apple using [ASCredentialExportManager](https://developer.apple.com/documentation/authenticationservices/ascredentialexportmanager).
93+
/// Ideally the output should be immediately deserialized to [ASExportedCredentialData](https://developer.apple.com/documentation/authenticationservices/asexportedcredentialdata).
94+
pub fn export_cxf(&self, ciphers: Vec<Cipher>) -> Result<String> {
95+
Ok(self
96+
.0
97+
.0
98+
.exporters()
99+
.export_cxf(ciphers)
100+
.map_err(Error::ExportError)?)
101+
}
89102
}

0 commit comments

Comments
 (0)