1use std::fmt;
2
3use bitwarden_vault::{
4 CipherRepromptType, CipherView, Fido2CredentialFullView, LoginUriView, UriMatchType,
5};
6use chrono::{DateTime, Utc};
7use uuid::Uuid;
8
9#[cfg(feature = "uniffi")]
10uniffi::setup_scaffolding!();
11#[cfg(feature = "uniffi")]
12mod uniffi_support;
13
14mod csv;
15mod cxf;
16pub use cxf::Account;
17mod encrypted_json;
18mod exporter_client;
19mod json;
20mod models;
21pub use exporter_client::{ExporterClient, ExporterClientExt};
22mod error;
23mod export;
24pub use error::ExportError;
25
26#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
27#[cfg_attr(
28 feature = "wasm",
29 derive(serde::Serialize, serde::Deserialize, tsify_next::Tsify),
30 tsify(into_wasm_abi, from_wasm_abi)
31)]
32pub enum ExportFormat {
33 Csv,
34 Json,
35 EncryptedJson { password: String },
36}
37
38pub struct Folder {
43 pub id: Uuid,
44 pub name: String,
45}
46
47#[derive(Clone)]
52pub struct Cipher {
53 pub id: Uuid,
54 pub folder_id: Option<Uuid>,
55
56 pub name: String,
57 pub notes: Option<String>,
58
59 pub r#type: CipherType,
60
61 pub favorite: bool,
62 pub reprompt: u8,
63
64 pub fields: Vec<Field>,
65
66 pub revision_date: DateTime<Utc>,
67 pub creation_date: DateTime<Utc>,
68 pub deleted_date: Option<DateTime<Utc>>,
69}
70
71#[derive(Clone)]
76pub struct ImportingCipher {
77 pub folder_id: Option<Uuid>,
78
79 pub name: String,
80 pub notes: Option<String>,
81
82 pub r#type: CipherType,
83
84 pub favorite: bool,
85 pub reprompt: u8,
86
87 pub fields: Vec<Field>,
88
89 pub revision_date: DateTime<Utc>,
90 pub creation_date: DateTime<Utc>,
91 pub deleted_date: Option<DateTime<Utc>>,
92}
93
94impl From<ImportingCipher> for CipherView {
95 fn from(value: ImportingCipher) -> Self {
96 let login = match value.r#type {
97 CipherType::Login(login) => {
98 let l: Vec<LoginUriView> = login
99 .login_uris
100 .into_iter()
101 .map(LoginUriView::from)
102 .collect();
103
104 Some(bitwarden_vault::LoginView {
105 username: login.username,
106 password: login.password,
107 password_revision_date: None,
108 uris: if l.is_empty() { None } else { Some(l) },
109 totp: login.totp,
110 autofill_on_page_load: None,
111 fido2_credentials: None,
112 })
113 }
114 _ => None,
115 };
116
117 Self {
118 id: None,
119 organization_id: None,
120 folder_id: value.folder_id,
121 collection_ids: vec![],
122 key: None,
123 name: value.name,
124 notes: None,
125 r#type: bitwarden_vault::CipherType::Login,
126 login,
127 identity: None,
128 card: None,
129 secure_note: None,
130 ssh_key: None,
131 favorite: value.favorite,
132 reprompt: CipherRepromptType::None,
133 organization_use_totp: true,
134 edit: true,
135 permissions: None,
136 view_password: true,
137 local_data: None,
138 attachments: None,
139 fields: None,
140 password_history: None,
141 creation_date: value.creation_date,
142 deleted_date: None,
143 revision_date: value.revision_date,
144 }
145 }
146}
147
148impl From<LoginUri> for bitwarden_vault::LoginUriView {
149 fn from(value: LoginUri) -> Self {
150 Self {
151 uri: value.uri,
152 r#match: value.r#match.and_then(|m| match m {
153 0 => Some(UriMatchType::Domain),
154 1 => Some(UriMatchType::Host),
155 2 => Some(UriMatchType::StartsWith),
156 3 => Some(UriMatchType::Exact),
157 4 => Some(UriMatchType::RegularExpression),
158 5 => Some(UriMatchType::Never),
159 _ => None,
160 }),
161 uri_checksum: None,
162 }
163 }
164}
165
166#[derive(Clone)]
167pub struct Field {
168 pub name: Option<String>,
169 pub value: Option<String>,
170 pub r#type: u8,
171 pub linked_id: Option<u32>,
172}
173
174#[derive(Clone)]
175pub enum CipherType {
176 Login(Box<Login>),
177 SecureNote(Box<SecureNote>),
178 Card(Box<Card>),
179 Identity(Box<Identity>),
180 SshKey(Box<SshKey>),
181}
182
183impl fmt::Display for CipherType {
184 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185 match self {
186 CipherType::Login(_) => write!(f, "login"),
187 CipherType::SecureNote(_) => write!(f, "note"),
188 CipherType::Card(_) => write!(f, "card"),
189 CipherType::Identity(_) => write!(f, "identity"),
190 CipherType::SshKey(_) => write!(f, "ssh_key"),
191 }
192 }
193}
194
195#[derive(Clone)]
196pub struct Login {
197 pub username: Option<String>,
198 pub password: Option<String>,
199 pub login_uris: Vec<LoginUri>,
200 pub totp: Option<String>,
201
202 pub fido2_credentials: Option<Vec<Fido2Credential>>,
203}
204
205#[derive(Clone)]
206pub struct LoginUri {
207 pub uri: Option<String>,
208 pub r#match: Option<u8>,
209}
210
211#[derive(Clone)]
212pub struct Fido2Credential {
213 pub credential_id: String,
214 pub key_type: String,
215 pub key_algorithm: String,
216 pub key_curve: String,
217 pub key_value: String,
218 pub rp_id: String,
219 pub user_handle: Option<String>,
220 pub user_name: Option<String>,
221 pub counter: u32,
222 pub rp_name: Option<String>,
223 pub user_display_name: Option<String>,
224 pub discoverable: String,
225 pub creation_date: DateTime<Utc>,
226}
227
228impl From<Fido2Credential> for Fido2CredentialFullView {
229 fn from(value: Fido2Credential) -> Self {
230 Fido2CredentialFullView {
231 credential_id: value.credential_id,
232 key_type: value.key_type,
233 key_algorithm: value.key_algorithm,
234 key_curve: value.key_curve,
235 key_value: value.key_value,
236 rp_id: value.rp_id,
237 user_handle: value.user_handle,
238 user_name: value.user_name,
239 counter: value.counter.to_string(),
240 rp_name: value.rp_name,
241 user_display_name: value.user_display_name,
242 discoverable: value.discoverable,
243 creation_date: value.creation_date,
244 }
245 }
246}
247
248#[derive(Clone)]
249pub struct Card {
250 pub cardholder_name: Option<String>,
251 pub exp_month: Option<String>,
252 pub exp_year: Option<String>,
253 pub code: Option<String>,
254 pub brand: Option<String>,
255 pub number: Option<String>,
256}
257
258#[derive(Clone)]
259pub struct SecureNote {
260 pub r#type: SecureNoteType,
261}
262
263#[derive(Clone)]
264pub enum SecureNoteType {
265 Generic = 0,
266}
267
268#[derive(Clone)]
269pub struct Identity {
270 pub title: Option<String>,
271 pub first_name: Option<String>,
272 pub middle_name: Option<String>,
273 pub last_name: Option<String>,
274 pub address1: Option<String>,
275 pub address2: Option<String>,
276 pub address3: Option<String>,
277 pub city: Option<String>,
278 pub state: Option<String>,
279 pub postal_code: Option<String>,
280 pub country: Option<String>,
281 pub company: Option<String>,
282 pub email: Option<String>,
283 pub phone: Option<String>,
284 pub ssn: Option<String>,
285 pub username: Option<String>,
286 pub passport_number: Option<String>,
287 pub license_number: Option<String>,
288}
289
290#[derive(Clone)]
291pub struct SshKey {
292 pub private_key: String,
294 pub public_key: String,
296 pub fingerprint: String,
298}