bitwarden_exporters/
export.rs1use bitwarden_collections::collection::Collection;
2use bitwarden_core::{key_management::KeyIds, Client};
3use bitwarden_crypto::{CompositeEncryptable, IdentifyKey, KeyStoreContext};
4use bitwarden_vault::{Cipher, CipherView, Folder, FolderView};
5
6use crate::{
7 csv::export_csv,
8 cxf::{build_cxf, parse_cxf, Account},
9 encrypted_json::export_encrypted_json,
10 json::export_json,
11 ExportError, ExportFormat, ImportingCipher,
12};
13
14pub(crate) fn export_vault(
15 client: &Client,
16 folders: Vec<Folder>,
17 ciphers: Vec<Cipher>,
18 format: ExportFormat,
19) -> Result<String, ExportError> {
20 let key_store = client.internal.get_key_store();
21
22 let folders: Vec<FolderView> = key_store.decrypt_list(&folders)?;
23 let folders: Vec<crate::Folder> = folders.into_iter().flat_map(|f| f.try_into()).collect();
24
25 let ciphers: Vec<crate::Cipher> = ciphers
26 .into_iter()
27 .flat_map(|c| crate::Cipher::from_cipher(key_store, c))
28 .collect();
29
30 match format {
31 ExportFormat::Csv => Ok(export_csv(folders, ciphers)?),
32 ExportFormat::Json => Ok(export_json(folders, ciphers)?),
33 ExportFormat::EncryptedJson { password } => Ok(export_encrypted_json(
34 folders,
35 ciphers,
36 password,
37 client.internal.get_kdf()?,
38 )?),
39 }
40}
41
42pub(crate) fn export_organization_vault(
43 _collections: Vec<Collection>,
44 _ciphers: Vec<Cipher>,
45 _format: ExportFormat,
46) -> Result<String, ExportError> {
47 todo!();
48}
49
50pub(crate) fn export_cxf(
52 client: &Client,
53 account: Account,
54 ciphers: Vec<Cipher>,
55) -> Result<String, ExportError> {
56 let key_store = client.internal.get_key_store();
57
58 let ciphers: Vec<crate::Cipher> = ciphers
59 .into_iter()
60 .flat_map(|c| crate::Cipher::from_cipher(key_store, c))
61 .collect();
62
63 Ok(build_cxf(account, ciphers)?)
64}
65
66fn encrypt_import(
67 ctx: &mut KeyStoreContext<KeyIds>,
68 cipher: ImportingCipher,
69) -> Result<Cipher, ExportError> {
70 let mut view: CipherView = cipher.clone().into();
71
72 let passkey = match cipher.r#type {
74 crate::CipherType::Login(login) => login.fido2_credentials,
75 _ => None,
76 };
77
78 if let Some(passkey) = passkey {
79 let passkeys = passkey.into_iter().map(|p| p.into()).collect();
80
81 view.set_new_fido2_credentials(ctx, passkeys)?;
82 }
83
84 let new_cipher = view.encrypt_composite(ctx, view.key_identifier())?;
85
86 Ok(new_cipher)
87}
88
89pub(crate) fn import_cxf(client: &Client, payload: String) -> Result<Vec<Cipher>, ExportError> {
91 let key_store = client.internal.get_key_store();
92 let mut ctx = key_store.context();
93
94 let ciphers = parse_cxf(payload)?;
95 let ciphers: Result<Vec<Cipher>, _> = ciphers
96 .into_iter()
97 .map(|c| encrypt_import(&mut ctx, c))
98 .collect();
99
100 ciphers
101}