Skip to content

Commit e0a4069

Browse files
committed
refactor(vault): replace fido2view with fido2fullview
1 parent 6c8b739 commit e0a4069

13 files changed

Lines changed: 129 additions & 337 deletions

File tree

crates/bitwarden-exporters/src/export.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub fn encrypt_import(
9292
if let Some(passkey) = passkey {
9393
let passkeys = passkey.into_iter().map(|p| p.into()).collect();
9494

95-
view.set_new_fido2_credentials(ctx, passkeys)?;
95+
view.set_new_fido2_credentials(passkeys)?;
9696
}
9797

9898
// Select the encryption format based on the account's current security state, matching how

crates/bitwarden-exporters/src/models.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl crate::Cipher {
2525
let view: CipherView = key_store.decrypt(&cipher)?;
2626

2727
let r = match view.r#type {
28-
CipherType::Login => crate::CipherType::Login(Box::new(from_login(&view, key_store)?)),
28+
CipherType::Login => crate::CipherType::Login(Box::new(from_login(&view)?)),
2929
CipherType::SecureNote => {
3030
let s = require!(view.secure_note);
3131
crate::CipherType::SecureNote(Box::new(s.into()))
@@ -93,10 +93,7 @@ impl From<PasswordHistoryView> for crate::PasswordHistory {
9393
}
9494

9595
/// Convert a `LoginView` into a `crate::Login`.
96-
fn from_login(
97-
view: &CipherView,
98-
key_store: &KeyStore<KeySlotIds>,
99-
) -> Result<crate::Login, MissingFieldError> {
96+
fn from_login(view: &CipherView) -> Result<crate::Login, MissingFieldError> {
10097
let l = require!(view.login.clone());
10198

10299
Ok(crate::Login {
@@ -110,7 +107,7 @@ fn from_login(
110107
.collect(),
111108
totp: l.totp,
112109
fido2_credentials: l.fido2_credentials.as_ref().and_then(|_| {
113-
let credentials = view.get_fido2_credentials(&mut key_store.context()).ok()?;
110+
let credentials = view.get_fido2_credentials().ok()?;
114111
if credentials.is_empty() {
115112
None
116113
} else {
@@ -269,9 +266,6 @@ mod tests {
269266

270267
#[test]
271268
fn test_from_login() {
272-
let key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac);
273-
let key_store = create_test_crypto_with_user_key(key);
274-
275269
let test_id: uuid::Uuid = "fd411a1a-fec8-4070-985d-0e6560860e69".parse().unwrap();
276270
let view = CipherView {
277271
r#type: CipherType::Login,
@@ -315,7 +309,7 @@ mod tests {
315309
archived_date: None,
316310
};
317311

318-
let login = from_login(&view, &key_store).unwrap();
312+
let login = from_login(&view).unwrap();
319313

320314
assert_eq!(login.username, Some("test_username".to_string()));
321315
assert_eq!(login.password, Some("test_password".to_string()));

crates/bitwarden-fido/src/authenticator.rs

Lines changed: 21 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -261,18 +261,16 @@ impl<'a> Fido2Authenticator<'a> {
261261
rp_id: String,
262262
user_handle: Option<Vec<u8>>,
263263
) -> Result<Vec<Fido2CredentialAutofillView>, SilentlyDiscoverCredentialsError> {
264-
let key_store = self.client.internal.get_key_store();
265264
let result = self
266265
.credential_store
267266
.find_credentials(None, rp_id, user_handle)
268267
.await?;
269268

270-
let mut ctx = key_store.context();
271269
result
272270
.into_iter()
273271
.map(
274272
|cipher| -> Result<Vec<Fido2CredentialAutofillView>, SilentlyDiscoverCredentialsError> {
275-
Ok(Fido2CredentialAutofillView::from_cipher_view(&cipher, &mut ctx)?)
273+
Ok(Fido2CredentialAutofillView::from_cipher_view(&cipher)?)
276274
},
277275
)
278276
.flatten_ok()
@@ -326,16 +324,14 @@ impl<'a> Fido2Authenticator<'a> {
326324
pub(super) fn get_selected_credential(
327325
&self,
328326
) -> Result<SelectedCredential, GetSelectedCredentialError> {
329-
let key_store = self.client.internal.get_key_store();
330-
331327
let cipher = self
332328
.selected_cipher
333329
.lock()
334330
.expect("Mutex is not poisoned")
335331
.clone()
336332
.ok_or(GetSelectedCredentialError::NoSelectedCredential)?;
337333

338-
let creds = cipher.decrypt_fido2_credentials(&mut key_store.context())?;
334+
let creds = cipher.decrypt_fido2_credentials();
339335

340336
let credential = creds
341337
.first()
@@ -400,13 +396,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
400396
})
401397
.collect();
402398

403-
let key_store = this.authenticator.client.internal.get_key_store();
404-
405399
// When using the credential for authentication we have to ask the user to pick one.
406400
if this.create_credential {
407401
Ok(creds
408402
.into_iter()
409-
.map(|c| CipherViewContainer::new(c, &mut key_store.context()))
403+
.map(CipherViewContainer::new)
410404
.collect::<Result<_, _>>()?)
411405
} else {
412406
let picked = this
@@ -422,10 +416,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
422416
.expect("Mutex is not poisoned")
423417
.replace(picked.clone());
424418

425-
Ok(vec![CipherViewContainer::new(
426-
picked,
427-
&mut key_store.context(),
428-
)?])
419+
Ok(vec![CipherViewContainer::new(picked)?])
429420
}
430421
}
431422

@@ -480,9 +471,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
480471
.clone()
481472
.ok_or(InnerError::NoSelectedCredential)?;
482473

483-
let key_store = this.authenticator.client.internal.get_key_store();
484-
485-
selected.set_new_fido2_credentials(&mut key_store.context(), vec![cred])?;
474+
selected.set_new_fido2_credentials(vec![cred])?;
486475

487476
// Store the updated credential for later use
488477
this.authenticator
@@ -553,10 +542,8 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> {
553542

554543
let cred = fill_with_credential(&selected.credential, cred)?;
555544

556-
let key_store = this.authenticator.client.internal.get_key_store();
557-
558545
let mut selected = selected.cipher;
559-
selected.set_new_fido2_credentials(&mut key_store.context(), vec![cred])?;
546+
selected.set_new_fido2_credentials(vec![cred])?;
560547

561548
// Store the updated credential for later use
562549
this.authenticator
@@ -679,15 +666,12 @@ fn map_ui_hint(hint: UiHint<'_, CipherViewContainer>) -> UiHint<'_, CipherView>
679666
#[cfg(test)]
680667
mod tests {
681668
use async_trait::async_trait;
682-
use bitwarden_core::{
683-
Client,
684-
key_management::{KeySlotIds, SymmetricKeySlotId},
685-
};
686-
use bitwarden_crypto::{KeyStoreContext, PrimitiveEncryptable, SymmetricCryptoKey};
669+
use bitwarden_core::{Client, key_management::SymmetricKeySlotId};
670+
use bitwarden_crypto::SymmetricCryptoKey;
687671
use bitwarden_encoding::B64Url;
688672
use bitwarden_vault::{
689673
CipherListView, CipherRepromptType, CipherType, CipherView, EncryptionContext,
690-
Fido2Credential, Fido2CredentialNewView, LoginView,
674+
Fido2CredentialFullView, Fido2CredentialNewView, LoginView,
691675
};
692676
use passkey::authenticator::UiHint;
693677

@@ -781,23 +765,22 @@ mod tests {
781765
0x84, 0x05, 0x71,
782766
];
783767

784-
fn create_test_cipher(ctx: &mut KeyStoreContext<KeySlotIds>) -> CipherView {
785-
let key = SymmetricKeySlotId::User;
768+
fn create_test_cipher() -> CipherView {
786769
let key_value = B64Url::from(TEST_FIDO_P256_KEY).to_string();
787770

788-
let fido2_credential = Fido2Credential {
789-
credential_id: TEST_FIDO_CREDENTIAL_ID.encrypt(ctx, key).unwrap(),
790-
key_type: "public-key".to_string().encrypt(ctx, key).unwrap(),
791-
key_algorithm: "ECDSA".to_string().encrypt(ctx, key).unwrap(),
792-
key_curve: "P-256".to_string().encrypt(ctx, key).unwrap(),
793-
key_value: key_value.encrypt(ctx, key).unwrap(),
794-
rp_id: TEST_FIDO_RP_ID.encrypt(ctx, key).unwrap(),
795-
user_handle: Some(TEST_FIDO_USER_HANDLE.encrypt(ctx, key).unwrap()),
771+
let fido2_credential = Fido2CredentialFullView {
772+
credential_id: TEST_FIDO_CREDENTIAL_ID.to_string(),
773+
key_type: "public-key".to_string(),
774+
key_algorithm: "ECDSA".to_string(),
775+
key_curve: "P-256".to_string(),
776+
key_value,
777+
rp_id: TEST_FIDO_RP_ID.to_string(),
778+
user_handle: Some(TEST_FIDO_USER_HANDLE.to_string()),
796779
user_name: None,
797-
counter: "0".to_string().encrypt(ctx, key).unwrap(),
780+
counter: "0".to_string(),
798781
rp_name: None,
799782
user_display_name: None,
800-
discoverable: "true".to_string().encrypt(ctx, key).unwrap(),
783+
discoverable: "true".to_string(),
801784
creation_date: "2024-06-07T14:12:36.150Z".parse().unwrap(),
802785
};
803786

@@ -865,10 +848,7 @@ mod tests {
865848
.set_symmetric_key(SymmetricKeySlotId::User, user_key)
866849
.unwrap();
867850

868-
let cipher = {
869-
let mut ctx = client.internal.get_key_store().context();
870-
create_test_cipher(&mut ctx)
871-
};
851+
let cipher = create_test_cipher();
872852

873853
let user_interface = MockUserInterface;
874854
let credential_store = MockCredentialStore { cipher };

crates/bitwarden-fido/src/client_fido.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ impl ClientFido2 {
6565
&self,
6666
cipher_view: CipherView,
6767
) -> Result<Vec<Fido2CredentialAutofillView>, DecryptFido2AutofillCredentialsError> {
68-
let key_store = self.client.internal.get_key_store();
69-
70-
Ok(Fido2CredentialAutofillView::from_cipher_view(
71-
&cipher_view,
72-
&mut key_store.context(),
73-
)?)
68+
Ok(Fido2CredentialAutofillView::from_cipher_view(&cipher_view)?)
7469
}
7570
}
7671

crates/bitwarden-fido/src/lib.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
#![doc = include_str!("../README.md")]
22

3-
use bitwarden_core::key_management::KeySlotIds;
4-
use bitwarden_crypto::KeyStoreContext;
53
use bitwarden_encoding::{B64Url, NotB64UrlEncodedError};
6-
use bitwarden_vault::{
7-
CipherError, CipherView, Fido2CredentialFullView, Fido2CredentialNewView, Fido2CredentialView,
8-
};
4+
use bitwarden_vault::{CipherError, CipherView, Fido2CredentialFullView, Fido2CredentialNewView};
95
use crypto::{CoseKeyToPkcs8Error, PrivateKeyFromSecretKeyError};
106
use passkey::types::{CredentialExtensions, Passkey, ctap2::Aaguid};
117

@@ -61,7 +57,7 @@ const AAGUID: Aaguid = Aaguid([
6157
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
6258
pub struct SelectedCredential {
6359
cipher: CipherView,
64-
credential: Fido2CredentialView,
60+
credential: Fido2CredentialFullView,
6561
}
6662

6763
// This container is needed so we can properly implement the TryFrom trait for Passkey
@@ -73,8 +69,8 @@ pub(crate) struct CipherViewContainer {
7369
}
7470

7571
impl CipherViewContainer {
76-
fn new(cipher: CipherView, ctx: &mut KeyStoreContext<KeySlotIds>) -> Result<Self, CipherError> {
77-
let fido2_credentials = cipher.get_fido2_credentials(ctx)?;
72+
fn new(cipher: CipherView) -> Result<Self, CipherError> {
73+
let fido2_credentials = cipher.get_fido2_credentials()?;
7874
Ok(Self {
7975
cipher,
8076
fido2_credentials,
@@ -149,7 +145,7 @@ pub enum FillCredentialError {
149145

150146
#[allow(missing_docs)]
151147
pub fn fill_with_credential(
152-
view: &Fido2CredentialView,
148+
view: &Fido2CredentialFullView,
153149
value: Passkey,
154150
) -> Result<Fido2CredentialFullView, FillCredentialError> {
155151
let cred_id: Vec<u8> = value.credential_id.into();

crates/bitwarden-fido/src/types.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{borrow::Cow, collections::HashMap};
22

3-
use bitwarden_core::key_management::KeySlotIds;
4-
use bitwarden_crypto::{CryptoError, KeyStoreContext};
3+
use bitwarden_crypto::CryptoError;
54
use bitwarden_encoding::{B64Url, NotB64UrlEncodedError};
65
use bitwarden_vault::{CipherListView, CipherListViewType, CipherView, LoginListView};
76
use passkey::types::webauthn::UserVerificationRequirement;
@@ -70,9 +69,8 @@ impl Fido2CredentialAutofillView {
7069
#[allow(missing_docs)]
7170
pub fn from_cipher_view(
7271
cipher: &CipherView,
73-
ctx: &mut KeyStoreContext<KeySlotIds>,
7472
) -> Result<Vec<Fido2CredentialAutofillView>, Fido2CredentialAutofillViewError> {
75-
let credentials = cipher.decrypt_fido2_credentials(ctx)?;
73+
let credentials = cipher.decrypt_fido2_credentials();
7674

7775
credentials
7876
.iter()

crates/bitwarden-uniffi/src/vault/ciphers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use bitwarden_collections::collection::CollectionId;
22
use bitwarden_core::OrganizationId;
33
use bitwarden_vault::{
44
Cipher, CipherListView, CipherView, DecryptCipherListResult, EncryptionContext,
5-
Fido2CredentialView,
5+
Fido2CredentialFullView,
66
};
77

88
use crate::Result;
@@ -42,7 +42,7 @@ impl CiphersClient {
4242
pub fn decrypt_fido2_credentials(
4343
&self,
4444
cipher_view: CipherView,
45-
) -> Result<Vec<Fido2CredentialView>> {
45+
) -> Result<Vec<Fido2CredentialFullView>> {
4646
Ok(self.0.decrypt_fido2_credentials(cipher_view)?)
4747
}
4848

crates/bitwarden-vault/src/cipher/blob/conversions/login.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,14 @@ impl From<&Fido2CredentialDataV1> for Fido2CredentialFullView {
6565

6666
#[cfg(test)]
6767
mod tests {
68-
use bitwarden_crypto::{CompositeEncryptable, Decryptable};
6968
use chrono::{TimeZone, Utc};
7069

7170
use super::super::{CipherBlobV1, CipherTypeDataV1, LoginUriDataV1, test_support::*};
7271
use crate::cipher::{
7372
cipher::CipherType,
7473
field::{FieldType, FieldView},
7574
linked_id::{LinkedIdType, LoginLinkedIdType},
76-
login::{Fido2Credential, Fido2CredentialFullView, LoginUriView, LoginView, UriMatchType},
75+
login::{Fido2CredentialFullView, LoginUriView, LoginView, UriMatchType},
7776
};
7877

7978
#[test]
@@ -185,7 +184,7 @@ mod tests {
185184
let (key_store, key_id) = create_test_key_store();
186185
let mut ctx = key_store.context_mut();
187186

188-
// Create fido2 credentials by encrypting a FullView
187+
// The decrypted login view holds fully-decrypted FIDO2 credentials.
189188
let fido2_full = Fido2CredentialFullView {
190189
credential_id: "cred-123".to_string(),
191190
key_type: "public-key".to_string(),
@@ -201,8 +200,6 @@ mod tests {
201200
discoverable: "true".to_string(),
202201
creation_date: Utc.with_ymd_and_hms(2024, 6, 1, 10, 30, 0).unwrap(),
203202
};
204-
let encrypted_fido2: Fido2Credential =
205-
fido2_full.encrypt_composite(&mut ctx, key_id).unwrap();
206203

207204
let original = crate::CipherView {
208205
name: "My Login".to_string(),
@@ -219,7 +216,7 @@ mod tests {
219216
}]),
220217
totp: Some("otpauth://totp/test?secret=JBSWY3DPEHPK3PXP".to_string()),
221218
autofill_on_page_load: Some(true),
222-
fido2_credentials: Some(vec![encrypted_fido2]),
219+
fido2_credentials: Some(vec![fido2_full]),
223220
}),
224221
fields: Some(vec![FieldView {
225222
name: Some("Custom Field".to_string()),
@@ -278,15 +275,13 @@ mod tests {
278275
assert_eq!(uris[0].r#match, Some(UriMatchType::Domain));
279276
assert_eq!(uris[0].uri_checksum, None);
280277

281-
// Fido2 credentials should be re-encrypted
278+
// Fido2 credentials round-trip as fully-decrypted views
282279
let fido2 = login.fido2_credentials.unwrap();
283280
assert_eq!(fido2.len(), 1);
284-
// Decrypt to verify content survived the round-trip
285-
let decrypted: Fido2CredentialFullView = fido2[0].decrypt(&mut ctx, key_id).unwrap();
286-
assert_eq!(decrypted.credential_id, "cred-123");
287-
assert_eq!(decrypted.counter, "42");
288-
assert_eq!(decrypted.discoverable, "true");
289-
assert_eq!(decrypted.rp_id, "example.com");
281+
assert_eq!(fido2[0].credential_id, "cred-123");
282+
assert_eq!(fido2[0].counter, "42");
283+
assert_eq!(fido2[0].discoverable, "true");
284+
assert_eq!(fido2[0].rp_id, "example.com");
290285

291286
// Fields and password history
292287
assert_eq!(restored.fields.as_ref().unwrap().len(), 1);

0 commit comments

Comments
 (0)