From f61d10496ea5724b639ba991a7b953a7852ca34c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garci=CC=81a?= Date: Wed, 12 Jun 2024 20:07:01 +0200 Subject: [PATCH] Make client internally mutable --- .../src/keys/asymmetric_crypto_key.rs | 1 + .../src/keys/key_encryptable.rs | 8 +- .../src/keys/symmetric_crypto_key.rs | 1 + .../bitwarden/src/auth/login/access_token.rs | 2 +- crates/bitwarden/src/auth/login/api_key.rs | 2 +- .../bitwarden/src/auth/login/auth_request.rs | 2 +- crates/bitwarden/src/auth/login/password.rs | 2 +- .../bitwarden/src/auth/password/validate.rs | 14 +- crates/bitwarden/src/auth/renew.rs | 37 ++-- crates/bitwarden/src/client/client.rs | 173 ++++++++++++------ .../src/client/encryption_settings.rs | 3 +- crates/bitwarden/src/mobile/crypto.rs | 52 ++---- .../bitwarden/src/mobile/tool/client_sends.rs | 7 +- .../src/mobile/vault/client_attachments.rs | 4 +- .../src/mobile/vault/client_ciphers.rs | 10 +- .../src/mobile/vault/client_collection.rs | 4 +- .../src/platform/fido2/authenticator.rs | 12 +- .../src/platform/get_user_api_key.rs | 11 +- .../src/secrets_manager/projects/create.rs | 6 +- .../src/secrets_manager/projects/get.rs | 2 +- .../src/secrets_manager/projects/list.rs | 2 +- .../src/secrets_manager/projects/update.rs | 6 +- .../src/secrets_manager/secrets/create.rs | 6 +- .../src/secrets_manager/secrets/get.rs | 2 +- .../src/secrets_manager/secrets/get_by_ids.rs | 2 +- .../src/secrets_manager/secrets/list.rs | 4 +- .../src/secrets_manager/secrets/sync.rs | 2 +- .../src/secrets_manager/secrets/update.rs | 6 +- crates/bitwarden/src/tool/exporters/mod.rs | 7 +- crates/bitwarden/src/vault/sync.rs | 2 +- 30 files changed, 219 insertions(+), 173 deletions(-) diff --git a/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs b/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs index be523bbc6..9a2bb43e3 100644 --- a/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs +++ b/crates/bitwarden-crypto/src/keys/asymmetric_crypto_key.rs @@ -36,6 +36,7 @@ impl AsymmetricEncryptable for AsymmetricPublicCryptoKey { /// An asymmetric encryption key. Contains both the public and private key. Can be used to both /// encrypt and decrypt [`AsymmetricEncString`](crate::AsymmetricEncString). +#[derive(Clone)] pub struct AsymmetricCryptoKey { // RsaPrivateKey is not a Copy type so this isn't completely necessary, but // to keep the compiler from making stack copies when moving this struct around, diff --git a/crates/bitwarden-crypto/src/keys/key_encryptable.rs b/crates/bitwarden-crypto/src/keys/key_encryptable.rs index d8f11a011..f1a538d12 100644 --- a/crates/bitwarden-crypto/src/keys/key_encryptable.rs +++ b/crates/bitwarden-crypto/src/keys/key_encryptable.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, hash::Hash}; +use std::{collections::HashMap, hash::Hash, sync::Arc}; use rayon::prelude::*; use uuid::Uuid; @@ -9,6 +9,12 @@ pub trait KeyContainer: Send + Sync { fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey>; } +impl KeyContainer for Arc { + fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey> { + self.as_ref().get_key(org_id) + } +} + pub trait LocateKey { fn locate_key<'a>( &self, diff --git a/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs b/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs index 4857aa2d4..971564b07 100644 --- a/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs +++ b/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs @@ -10,6 +10,7 @@ use super::key_encryptable::CryptoKey; use crate::CryptoError; /// A symmetric encryption key. Used to encrypt and decrypt [`EncString`](crate::EncString) +#[derive(Clone)] pub struct SymmetricCryptoKey { // GenericArray is equivalent to [u8; N], which is a Copy type placed on the stack. // To keep the compiler from making stack copies when moving this struct around, diff --git a/crates/bitwarden/src/auth/login/access_token.rs b/crates/bitwarden/src/auth/login/access_token.rs index 932591470..25d8ffb5d 100644 --- a/crates/bitwarden/src/auth/login/access_token.rs +++ b/crates/bitwarden/src/auth/login/access_token.rs @@ -104,7 +104,7 @@ async fn request_access_token( ) -> Result { let config = client.get_api_configurations().await; AccessTokenRequest::new(input.access_token_id, &input.client_secret) - .send(config) + .send(&config) .await } diff --git a/crates/bitwarden/src/auth/login/api_key.rs b/crates/bitwarden/src/auth/login/api_key.rs index 1361afe34..92f1c76b9 100644 --- a/crates/bitwarden/src/auth/login/api_key.rs +++ b/crates/bitwarden/src/auth/login/api_key.rs @@ -63,7 +63,7 @@ async fn request_api_identity_tokens( ) -> Result { let config = client.get_api_configurations().await; ApiTokenRequest::new(&input.client_id, &input.client_secret) - .send(config) + .send(&config) .await } diff --git a/crates/bitwarden/src/auth/login/auth_request.rs b/crates/bitwarden/src/auth/login/auth_request.rs index 334cede99..380a49b9d 100644 --- a/crates/bitwarden/src/auth/login/auth_request.rs +++ b/crates/bitwarden/src/auth/login/auth_request.rs @@ -81,7 +81,7 @@ pub(crate) async fn complete_auth_request( config.device_type, &auth_req.device_identifier, ) - .send(config) + .send(&config) .await?; if let IdentityTokenResponse::Authenticated(r) = response { diff --git a/crates/bitwarden/src/auth/login/password.rs b/crates/bitwarden/src/auth/login/password.rs index 592f204bb..bbbae3d1a 100644 --- a/crates/bitwarden/src/auth/login/password.rs +++ b/crates/bitwarden/src/auth/login/password.rs @@ -76,7 +76,7 @@ async fn request_identity_tokens( "b86dd6ab-4265-4ddf-a7f1-eb28d5677f33", &input.two_factor, ) - .send(config) + .send(&config) .await } diff --git a/crates/bitwarden/src/auth/password/validate.rs b/crates/bitwarden/src/auth/password/validate.rs index 5cd5875bb..2a077418a 100644 --- a/crates/bitwarden/src/auth/password/validate.rs +++ b/crates/bitwarden/src/auth/password/validate.rs @@ -13,12 +13,9 @@ pub(crate) fn validate_password( password: String, password_hash: String, ) -> Result { - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - if let LoginMethod::User(login_method) = login_method { + if let LoginMethod::User(login_method) = login_method.as_ref() { match login_method { UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. } => { @@ -45,12 +42,9 @@ pub(crate) fn validate_password_user_key( ) -> Result { use bitwarden_core::VaultLocked; - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - if let LoginMethod::User(login_method) = login_method { + if let LoginMethod::User(login_method) = login_method.as_ref() { match login_method { UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. } => { diff --git a/crates/bitwarden/src/auth/renew.rs b/crates/bitwarden/src/auth/renew.rs index cd7c140c5..79cbf7e7e 100644 --- a/crates/bitwarden/src/auth/renew.rs +++ b/crates/bitwarden/src/auth/renew.rs @@ -12,26 +12,41 @@ use crate::{ pub(crate) async fn renew_token(client: &Client) -> Result<()> { const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60; - if let (Some(expires), Some(login_method)) = (&client.token_expires_on, &client.login_method) { + let expires = *client + .token_expires_on + .read() + .expect("RwLock is not poisoned"); + let login_method = client + .login_method + .read() + .expect("RwLock is not poisoned") + .clone(); + + if let (Some(expires), Some(login_method)) = (expires, login_method) { if Utc::now().timestamp() < expires - TOKEN_RENEW_MARGIN_SECONDS { return Ok(()); } - let res = match login_method { + let config = client + .__api_configurations + .read() + .expect("RwLock is not poisoned") + .clone(); + + let res = match login_method.as_ref() { #[cfg(feature = "internal")] LoginMethod::User(u) => match u { UserLoginMethod::Username { client_id, .. } => { let refresh = client .refresh_token - .as_deref() + .read() + .expect("RwLock is not poisoned") + .clone() .ok_or(Error::NotAuthenticated)?; - crate::auth::api::request::RenewTokenRequest::new( - refresh.to_owned(), - client_id.to_owned(), - ) - .send(&client.__api_configurations) - .await? + crate::auth::api::request::RenewTokenRequest::new(refresh, client_id.to_owned()) + .send(&config) + .await? } UserLoginMethod::ApiKey { client_id, @@ -39,7 +54,7 @@ pub(crate) async fn renew_token(client: &Client) -> Result<()> { .. } => { ApiTokenRequest::new(client_id, client_secret) - .send(&client.__api_configurations) + .send(&config) .await? } }, @@ -53,7 +68,7 @@ pub(crate) async fn renew_token(client: &Client) -> Result<()> { access_token.access_token_id, &access_token.client_secret, ) - .send(&client.__api_configurations) + .send(&config) .await?; if let (IdentityTokenResponse::Payload(r), Some(state_file), Ok(enc_settings)) = diff --git a/crates/bitwarden/src/client/client.rs b/crates/bitwarden/src/client/client.rs index 3c2238199..b4e087e4c 100644 --- a/crates/bitwarden/src/client/client.rs +++ b/crates/bitwarden/src/client/client.rs @@ -1,4 +1,7 @@ -use std::path::PathBuf; +use std::{ + path::PathBuf, + sync::{Arc, RwLock}, +}; use bitwarden_core::VaultLocked; #[cfg(feature = "internal")] @@ -21,13 +24,10 @@ use crate::{ error::Result, }; -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct ApiConfigurations { pub identity: bitwarden_api_identity::apis::configuration::Configuration, pub api: bitwarden_api_api::apis::configuration::Configuration, - /// Reqwest client useable for external integrations like email forwarders, HIBP. - #[allow(unused)] - pub external_client: reqwest::Client, pub device_type: DeviceType, } @@ -69,20 +69,24 @@ pub(crate) enum ServiceAccountLoginMethod { /// The main struct to interact with the Bitwarden SDK. #[derive(Debug)] pub struct Client { - token: Option, - pub(crate) refresh_token: Option, - pub(crate) token_expires_on: Option, - pub(crate) login_method: Option, + token: RwLock>, + pub(crate) refresh_token: RwLock>, + pub(crate) token_expires_on: RwLock>, + pub(crate) login_method: RwLock>>, #[cfg(feature = "internal")] - flags: Flags, + flags: RwLock, /// Use Client::get_api_configurations() to access this. /// It should only be used directly in renew_token #[doc(hidden)] - pub(crate) __api_configurations: ApiConfigurations, + pub(crate) __api_configurations: RwLock>, + + /// Reqwest client useable for external integrations like email forwarders, HIBP. + #[allow(unused)] + pub(crate) external_client: reqwest::Client, - encryption_settings: Option, + encryption_settings: RwLock>>, } impl Client { @@ -135,81 +139,113 @@ impl Client { }; Self { - token: None, - refresh_token: None, - token_expires_on: None, - login_method: None, + token: RwLock::new(None), + refresh_token: RwLock::new(None), + token_expires_on: RwLock::new(None), + login_method: RwLock::new(None), #[cfg(feature = "internal")] - flags: Flags::default(), - __api_configurations: ApiConfigurations { + flags: RwLock::new(Flags::default()), + __api_configurations: RwLock::new(Arc::new(ApiConfigurations { identity, api, - external_client, device_type: settings.device_type, - }, - encryption_settings: None, + })), + external_client, + encryption_settings: RwLock::new(None), } } #[cfg(feature = "internal")] pub fn load_flags(&self, flags: std::collections::HashMap) { - self.flags = Flags::load_from_map(flags); + *self.flags.write().expect("RwLock is not poisoned") = Flags::load_from_map(flags); } #[cfg(feature = "internal")] - pub(crate) fn get_flags(&self) -> &Flags { - &self.flags + pub(crate) fn get_flags(&self) -> Flags { + self.flags.read().expect("RwLock is not poisoned").clone() } - pub(crate) async fn get_api_configurations(&self) -> &ApiConfigurations { + pub(crate) async fn get_api_configurations(&self) -> Arc { // At the moment we ignore the error result from the token renewal, if it fails, // the token will end up expiring and the next operation is going to fail anyway. self.auth().renew_token().await.ok(); - &self.__api_configurations + self.__api_configurations + .read() + .expect("RwLock is not poisoned") + .clone() } #[cfg(feature = "internal")] pub(crate) fn get_http_client(&self) -> &reqwest::Client { - &self.__api_configurations.external_client + &self.external_client } #[cfg(feature = "internal")] - pub(crate) fn get_login_method(&self) -> &Option { - &self.login_method + pub(crate) fn get_login_method(&self) -> Option> { + self.login_method + .read() + .expect("RwLock is not poisoned") + .clone() } pub fn get_access_token_organization(&self) -> Option { - match self.login_method { + match self + .login_method + .read() + .expect("RwLock is not poisoned") + .as_deref() + { Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { organization_id, .. - })) => Some(organization_id), + })) => Some(*organization_id), _ => None, } } - pub(crate) fn get_encryption_settings(&self) -> Result<&EncryptionSettings> { - self.encryption_settings.as_ref().ok_or(VaultLocked.into()) + pub(crate) fn get_encryption_settings(&self) -> Result> { + self.encryption_settings + .read() + .expect("RwLock is not poisoned") + .clone() + .ok_or(VaultLocked.into()) } pub(crate) fn set_login_method(&self, login_method: LoginMethod) { use log::debug; debug! {"setting login method: {:#?}", login_method} - self.login_method = Some(login_method); + *self.login_method.write().expect("RwLock is not poisoned") = Some(Arc::new(login_method)); } pub(crate) fn set_tokens(&self, token: String, refresh_token: Option, expires_in: u64) { - self.token = Some(token.clone()); - self.refresh_token = refresh_token; - self.token_expires_on = Some(Utc::now().timestamp() + expires_in as i64); - self.__api_configurations.identity.oauth_access_token = Some(token.clone()); - self.__api_configurations.api.oauth_access_token = Some(token); + *self.token.write().expect("RwLock is not poisoned") = Some(token.clone()); + *self.refresh_token.write().expect("RwLock is not poisoned") = refresh_token; + *self + .token_expires_on + .write() + .expect("RwLock is not poisoned") = Some(Utc::now().timestamp() + expires_in as i64); + + let mut guard = self + .__api_configurations + .write() + .expect("RwLock is not poisoned"); + + let mut inner: ApiConfigurations = guard.as_ref().clone(); + inner.identity.oauth_access_token = Some(token.clone()); + inner.api.oauth_access_token = Some(token); + + *guard = Arc::new(inner); } #[cfg(feature = "internal")] pub fn is_authed(&self) -> bool { - self.token.is_some() || self.login_method.is_some() + self.token.read().expect("RwLock is not poisoned").is_some() + || self + .login_method + .read() + .expect("RwLock is not poisoned") + .is_some() } #[cfg(feature = "internal")] @@ -218,12 +254,17 @@ impl Client { master_key: MasterKey, user_key: EncString, private_key: EncString, - ) -> Result<&EncryptionSettings> { - Ok(self.encryption_settings.insert(EncryptionSettings::new( + ) -> Result<()> { + *self + .encryption_settings + .write() + .expect("RwLock is not poisoned") = Some(Arc::new(EncryptionSettings::new( master_key, user_key, private_key, - )?)) + )?)); + + Ok(()) } #[cfg(feature = "internal")] @@ -231,13 +272,15 @@ impl Client { &self, user_key: SymmetricCryptoKey, private_key: EncString, - ) -> Result<&EncryptionSettings> { - Ok(self + ) -> Result<()> { + *self .encryption_settings - .insert(EncryptionSettings::new_decrypted_key( - user_key, - private_key, - )?)) + .write() + .expect("RwLock is not poisoned") = Some(Arc::new( + EncryptionSettings::new_decrypted_key(user_key, private_key)?, + )); + + Ok(()) } #[cfg(feature = "internal")] @@ -246,28 +289,40 @@ impl Client { pin_key: MasterKey, pin_protected_user_key: EncString, private_key: EncString, - ) -> Result<&EncryptionSettings> { + ) -> Result<()> { let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?; self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key) } - pub(crate) fn initialize_crypto_single_key( - &self, - key: SymmetricCryptoKey, - ) -> &EncryptionSettings { - self.encryption_settings - .insert(EncryptionSettings::new_single_key(key)) + pub(crate) fn initialize_crypto_single_key(&self, key: SymmetricCryptoKey) { + *self + .encryption_settings + .write() + .expect("RwLock is not poisoned") = + Some(Arc::new(EncryptionSettings::new_single_key(key))); } #[cfg(feature = "internal")] pub(crate) fn initialize_org_crypto( &self, org_keys: Vec<(Uuid, AsymmetricEncString)>, - ) -> Result<&EncryptionSettings> { - let enc = self.encryption_settings.as_mut().ok_or(VaultLocked)?; + ) -> Result> { + let mut guard = self + .encryption_settings + .write() + .expect("RwLock is not poisoned"); + let Some(enc) = guard.as_mut() else { + return Err(VaultLocked.into()); + }; + + let mut enc: EncryptionSettings = enc.as_ref().clone(); enc.set_org_keys(org_keys)?; - Ok(&*enc) + let enc = Arc::new(enc); + + *guard = Some(enc.clone()); + + Ok(enc) } } diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden/src/client/encryption_settings.rs index 0cf91e45d..f92dd5f09 100644 --- a/crates/bitwarden/src/client/encryption_settings.rs +++ b/crates/bitwarden/src/client/encryption_settings.rs @@ -8,6 +8,7 @@ use uuid::Uuid; #[cfg(feature = "internal")] use crate::error::Result; +#[derive(Clone)] pub struct EncryptionSettings { user_key: SymmetricCryptoKey, pub(crate) private_key: Option, @@ -70,7 +71,7 @@ impl EncryptionSettings { pub(crate) fn set_org_keys( &mut self, org_enc_keys: Vec<(Uuid, AsymmetricEncString)>, - ) -> Result<&mut Self> { + ) -> Result<&Self> { use bitwarden_core::VaultLocked; use bitwarden_crypto::KeyDecryptable; diff --git a/crates/bitwarden/src/mobile/crypto.rs b/crates/bitwarden/src/mobile/crypto.rs index 2f6a2444f..fde041e5f 100644 --- a/crates/bitwarden/src/mobile/crypto.rs +++ b/crates/bitwarden/src/mobile/crypto.rs @@ -173,10 +173,8 @@ pub async fn initialize_org_crypto(client: &Client, req: InitOrgCryptoRequest) - #[cfg(feature = "internal")] pub async fn get_user_encryption_key(client: &Client) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; + let enc = client.get_encryption_settings()?; + let user_key = enc.get_key(&None).ok_or(VaultLocked)?; Ok(user_key.to_base64()) } @@ -193,18 +191,13 @@ pub struct UpdatePasswordResponse { } pub fn update_password(client: &Client, new_password: String) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; + let enc = client.get_encryption_settings()?; + let user_key = enc.get_key(&None).ok_or(VaultLocked)?; - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; // Derive a new master key from password - let new_master_key = match login_method { + let new_master_key = match login_method.as_ref() { LoginMethod::User( UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. }, @@ -238,17 +231,12 @@ pub struct DerivePinKeyResponse { #[cfg(feature = "internal")] pub fn derive_pin_key(client: &Client, pin: String) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; + let enc = client.get_encryption_settings()?; + let user_key = enc.get_key(&None).ok_or(VaultLocked)?; - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - let pin_protected_user_key = derive_pin_protected_user_key(&pin, login_method, user_key)?; + let pin_protected_user_key = derive_pin_protected_user_key(&pin, &login_method, user_key)?; Ok(DerivePinKeyResponse { pin_protected_user_key, @@ -258,18 +246,13 @@ pub fn derive_pin_key(client: &Client, pin: String) -> Result Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; + let enc = client.get_encryption_settings()?; + let user_key = enc.get_key(&None).ok_or(VaultLocked)?; let pin: String = encrypted_pin.decrypt_with_key(user_key)?; - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - derive_pin_protected_user_key(&pin, login_method, user_key) + derive_pin_protected_user_key(&pin, &login_method, user_key) } #[cfg(feature = "internal")] @@ -516,11 +499,8 @@ mod tests { AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key).unwrap()).unwrap(); let decrypted: Vec = encrypted.decrypt_with_key(&private_key).unwrap(); - let expected = client - .get_encryption_settings() - .unwrap() - .get_key(&None) - .unwrap(); + let enc = client.get_encryption_settings().unwrap(); + let expected = enc.get_key(&None).unwrap(); assert_eq!(&decrypted, &expected.to_vec()); } } diff --git a/crates/bitwarden/src/mobile/tool/client_sends.rs b/crates/bitwarden/src/mobile/tool/client_sends.rs index 6b0a14e4e..65c9d630c 100644 --- a/crates/bitwarden/src/mobile/tool/client_sends.rs +++ b/crates/bitwarden/src/mobile/tool/client_sends.rs @@ -75,11 +75,8 @@ impl<'a> ClientSends<'a> { } pub async fn encrypt_buffer(&self, send: Send, buffer: &[u8]) -> Result> { - let key = self - .client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; + let enc = self.client.get_encryption_settings()?; + let key = enc.get_key(&None).ok_or(VaultLocked)?; let key = Send::get_key(&send.key, key)?; let enc = buffer.encrypt_with_key(&key)?; diff --git a/crates/bitwarden/src/mobile/vault/client_attachments.rs b/crates/bitwarden/src/mobile/vault/client_attachments.rs index ce7570fab..aa5d75217 100644 --- a/crates/bitwarden/src/mobile/vault/client_attachments.rs +++ b/crates/bitwarden/src/mobile/vault/client_attachments.rs @@ -24,7 +24,7 @@ impl<'a> ClientAttachments<'a> { buffer: &[u8], ) -> Result { let enc = self.client.get_encryption_settings()?; - let key = cipher.locate_key(enc, &None).ok_or(VaultLocked)?; + let key = cipher.locate_key(&enc, &None).ok_or(VaultLocked)?; Ok(AttachmentFileView { cipher, @@ -56,7 +56,7 @@ impl<'a> ClientAttachments<'a> { encrypted_buffer: &[u8], ) -> Result> { let enc = self.client.get_encryption_settings()?; - let key = cipher.locate_key(enc, &None).ok_or(VaultLocked)?; + let key = cipher.locate_key(&enc, &None).ok_or(VaultLocked)?; AttachmentFile { cipher, diff --git a/crates/bitwarden/src/mobile/vault/client_ciphers.rs b/crates/bitwarden/src/mobile/vault/client_ciphers.rs index 8f1c899f6..c602e44a6 100644 --- a/crates/bitwarden/src/mobile/vault/client_ciphers.rs +++ b/crates/bitwarden/src/mobile/vault/client_ciphers.rs @@ -16,11 +16,11 @@ impl<'a> ClientCiphers<'a> { // TODO: Once this flag is removed, the key generation logic should // be moved directly into the KeyEncryptable implementation if cipher_view.key.is_none() && self.client.get_flags().enable_cipher_key_encryption { - let key = cipher_view.locate_key(enc, &None).ok_or(VaultLocked)?; + let key = cipher_view.locate_key(&enc, &None).ok_or(VaultLocked)?; cipher_view.generate_cipher_key(key)?; } - let key = cipher_view.locate_key(enc, &None).ok_or(VaultLocked)?; + let key = cipher_view.locate_key(&enc, &None).ok_or(VaultLocked)?; let cipher = cipher_view.encrypt_with_key(key)?; Ok(cipher) @@ -29,7 +29,7 @@ impl<'a> ClientCiphers<'a> { pub async fn decrypt(&self, cipher: Cipher) -> Result { let enc = self.client.get_encryption_settings()?; let key = cipher - .locate_key(enc, &None) + .locate_key(&enc, &None) .ok_or(CryptoError::MissingKey)?; let cipher_view = cipher.decrypt_with_key(key)?; @@ -43,7 +43,7 @@ impl<'a> ClientCiphers<'a> { let cipher_views: Result> = ciphers .iter() .map(|c| -> Result { - let key = c.locate_key(enc, &None).ok_or(CryptoError::MissingKey)?; + let key = c.locate_key(&enc, &None).ok_or(CryptoError::MissingKey)?; Ok(c.decrypt_with_key(key)?) }) .collect(); @@ -57,7 +57,7 @@ impl<'a> ClientCiphers<'a> { organization_id: Uuid, ) -> Result { let enc = self.client.get_encryption_settings()?; - cipher_view.move_to_organization(enc, organization_id)?; + cipher_view.move_to_organization(&enc, organization_id)?; Ok(cipher_view) } } diff --git a/crates/bitwarden/src/mobile/vault/client_collection.rs b/crates/bitwarden/src/mobile/vault/client_collection.rs index f6f5f9802..b75bd9841 100644 --- a/crates/bitwarden/src/mobile/vault/client_collection.rs +++ b/crates/bitwarden/src/mobile/vault/client_collection.rs @@ -11,7 +11,7 @@ impl<'a> ClientCollections<'a> { pub async fn decrypt(&self, collection: Collection) -> Result { let enc = self.client.get_encryption_settings()?; let key = collection - .locate_key(enc, &None) + .locate_key(&enc, &None) .ok_or(CryptoError::MissingKey)?; let view = collection.decrypt_with_key(key)?; @@ -25,7 +25,7 @@ impl<'a> ClientCollections<'a> { let views: Result> = collections .iter() .map(|c| -> Result { - let key = c.locate_key(enc, &None).ok_or(CryptoError::MissingKey)?; + let key = c.locate_key(&enc, &None).ok_or(CryptoError::MissingKey)?; Ok(c.decrypt_with_key(key)?) }) .collect(); diff --git a/crates/bitwarden/src/platform/fido2/authenticator.rs b/crates/bitwarden/src/platform/fido2/authenticator.rs index 6a141f0df..06d64f3b3 100644 --- a/crates/bitwarden/src/platform/fido2/authenticator.rs +++ b/crates/bitwarden/src/platform/fido2/authenticator.rs @@ -167,7 +167,7 @@ impl<'a> Fido2Authenticator<'a> { Ok(result .into_iter() - .flat_map(|c| c.decrypt_fido2_credentials(enc)) + .flat_map(|c| c.decrypt_fido2_credentials(&enc)) .flatten() .collect()) } @@ -208,7 +208,7 @@ impl<'a> Fido2Authenticator<'a> { .clone() .ok_or("No selected credential available")?; - let creds = cipher.decrypt_fido2_credentials(enc)?; + let creds = cipher.decrypt_fido2_credentials(&enc)?; let credential = creds.first().ok_or("No Fido2 credentials found")?.clone(); @@ -264,7 +264,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { if this.create_credential { creds .into_iter() - .map(|c| CipherViewContainer::new(c, enc)) + .map(|c| CipherViewContainer::new(c, &enc)) .collect() } else { let picked = this @@ -280,7 +280,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { .expect("Mutex is not poisoned") .replace(picked.clone()); - Ok(vec![CipherViewContainer::new(picked, enc)?]) + Ok(vec![CipherViewContainer::new(picked, &enc)?]) } } @@ -319,7 +319,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { .clone() .ok_or("No selected cipher available")?; - selected.set_new_fido2_credentials(enc, vec![cred])?; + selected.set_new_fido2_credentials(&enc, vec![cred])?; // Store the updated credential for later use this.authenticator @@ -366,7 +366,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { let cred = fill_with_credential(&selected.credential, cred)?; let mut selected = selected.cipher; - selected.set_new_fido2_credentials(enc, vec![cred])?; + selected.set_new_fido2_credentials(&enc, vec![cred])?; // Store the updated credential for later use this.authenticator diff --git a/crates/bitwarden/src/platform/get_user_api_key.rs b/crates/bitwarden/src/platform/get_user_api_key.rs index b2815058b..991040aaf 100644 --- a/crates/bitwarden/src/platform/get_user_api_key.rs +++ b/crates/bitwarden/src/platform/get_user_api_key.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use bitwarden_api_api::{ apis::accounts_api::accounts_api_key_post, models::{ApiKeyResponseModel, SecretVerificationRequestModel}, @@ -23,7 +25,7 @@ pub(crate) async fn get_user_api_key( debug!("{:?}", input); let auth_settings = get_login_method(client)?; - let request = get_secret_verification_request(auth_settings, input)?; + let request = get_secret_verification_request(&auth_settings, input)?; let config = client.get_api_configurations().await; @@ -31,12 +33,9 @@ pub(crate) async fn get_user_api_key( UserApiKeyResponse::process_response(response) } -fn get_login_method(client: &Client) -> Result<&LoginMethod> { +fn get_login_method(client: &Client) -> Result> { if client.is_authed() { - client - .get_login_method() - .as_ref() - .ok_or(Error::NotAuthenticated) + client.get_login_method().ok_or(Error::NotAuthenticated) } else { Err(Error::NotAuthenticated) } diff --git a/crates/bitwarden/src/secrets_manager/projects/create.rs b/crates/bitwarden/src/secrets_manager/projects/create.rs index 1f82d4c59..a0ef48548 100644 --- a/crates/bitwarden/src/secrets_manager/projects/create.rs +++ b/crates/bitwarden/src/secrets_manager/projects/create.rs @@ -21,8 +21,8 @@ pub(crate) async fn create_project( client: &mut Client, input: &ProjectCreateRequest, ) -> Result { - let key = client - .get_encryption_settings()? + let enc = client.get_encryption_settings()?; + let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -40,5 +40,5 @@ pub(crate) async fn create_project( let enc = client.get_encryption_settings()?; - ProjectResponse::process_response(res, enc) + ProjectResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/projects/get.rs b/crates/bitwarden/src/secrets_manager/projects/get.rs index 00afaa194..3e8b7f94a 100644 --- a/crates/bitwarden/src/secrets_manager/projects/get.rs +++ b/crates/bitwarden/src/secrets_manager/projects/get.rs @@ -22,5 +22,5 @@ pub(crate) async fn get_project( let enc = client.get_encryption_settings()?; - ProjectResponse::process_response(res, enc) + ProjectResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/projects/list.rs b/crates/bitwarden/src/secrets_manager/projects/list.rs index 5c491e14b..d5c7d4475 100644 --- a/crates/bitwarden/src/secrets_manager/projects/list.rs +++ b/crates/bitwarden/src/secrets_manager/projects/list.rs @@ -29,7 +29,7 @@ pub(crate) async fn list_projects( let enc = client.get_encryption_settings()?; - ProjectsResponse::process_response(res, enc) + ProjectsResponse::process_response(res, &enc) } #[derive(Serialize, Deserialize, Debug, JsonSchema)] diff --git a/crates/bitwarden/src/secrets_manager/projects/update.rs b/crates/bitwarden/src/secrets_manager/projects/update.rs index 86c269b1a..19ffd3e27 100644 --- a/crates/bitwarden/src/secrets_manager/projects/update.rs +++ b/crates/bitwarden/src/secrets_manager/projects/update.rs @@ -23,8 +23,8 @@ pub(crate) async fn update_project( client: &mut Client, input: &ProjectPutRequest, ) -> Result { - let key = client - .get_encryption_settings()? + let enc = client.get_encryption_settings()?; + let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -39,5 +39,5 @@ pub(crate) async fn update_project( let enc = client.get_encryption_settings()?; - ProjectResponse::process_response(res, enc) + ProjectResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/secrets/create.rs b/crates/bitwarden/src/secrets_manager/secrets/create.rs index 67f2a695e..6c750f194 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/create.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/create.rs @@ -26,8 +26,8 @@ pub(crate) async fn create_secret( client: &mut Client, input: &SecretCreateRequest, ) -> Result { - let key = client - .get_encryption_settings()? + let enc = client.get_encryption_settings()?; + let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -48,5 +48,5 @@ pub(crate) async fn create_secret( let enc = client.get_encryption_settings()?; - SecretResponse::process_response(res, enc) + SecretResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/secrets/get.rs b/crates/bitwarden/src/secrets_manager/secrets/get.rs index 622253a55..eca4b410a 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/get.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/get.rs @@ -21,5 +21,5 @@ pub(crate) async fn get_secret( let enc = client.get_encryption_settings()?; - SecretResponse::process_response(res, enc) + SecretResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs b/crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs index 032962849..1575043d2 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs @@ -26,5 +26,5 @@ pub(crate) async fn get_secrets_by_ids( let enc = client.get_encryption_settings()?; - SecretsResponse::process_response(res, enc) + SecretsResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/secrets_manager/secrets/list.rs b/crates/bitwarden/src/secrets_manager/secrets/list.rs index a5d263253..796aafe5d 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/list.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/list.rs @@ -32,7 +32,7 @@ pub(crate) async fn list_secrets( let enc = client.get_encryption_settings()?; - SecretIdentifiersResponse::process_response(res, enc) + SecretIdentifiersResponse::process_response(res, &enc) } #[derive(Serialize, Deserialize, Debug, JsonSchema)] @@ -55,7 +55,7 @@ pub(crate) async fn list_secrets_by_project( let enc = client.get_encryption_settings()?; - SecretIdentifiersResponse::process_response(res, enc) + SecretIdentifiersResponse::process_response(res, &enc) } #[derive(Serialize, Deserialize, Debug, JsonSchema)] diff --git a/crates/bitwarden/src/secrets_manager/secrets/sync.rs b/crates/bitwarden/src/secrets_manager/secrets/sync.rs index 565f25ecb..06c343ef7 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/sync.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/sync.rs @@ -33,7 +33,7 @@ pub(crate) async fn sync_secrets( let enc = client.get_encryption_settings()?; - SecretsSyncResponse::process_response(res, enc) + SecretsSyncResponse::process_response(res, &enc) } #[derive(Serialize, Deserialize, Debug, JsonSchema)] diff --git a/crates/bitwarden/src/secrets_manager/secrets/update.rs b/crates/bitwarden/src/secrets_manager/secrets/update.rs index a25900151..512368350 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/update.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/update.rs @@ -26,8 +26,8 @@ pub(crate) async fn update_secret( client: &mut Client, input: &SecretPutRequest, ) -> Result { - let key = client - .get_encryption_settings()? + let enc = client.get_encryption_settings()?; + let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -44,5 +44,5 @@ pub(crate) async fn update_secret( let enc = client.get_encryption_settings()?; - SecretResponse::process_response(res, enc) + SecretResponse::process_response(res, &enc) } diff --git a/crates/bitwarden/src/tool/exporters/mod.rs b/crates/bitwarden/src/tool/exporters/mod.rs index 711eb88e6..0c87bc558 100644 --- a/crates/bitwarden/src/tool/exporters/mod.rs +++ b/crates/bitwarden/src/tool/exporters/mod.rs @@ -47,12 +47,9 @@ fn convert_format( client: &Client, format: ExportFormat, ) -> Result { - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; + let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - let kdf = match login_method { + let kdf = match login_method.as_ref() { LoginMethod::User( UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, ) => kdf, diff --git a/crates/bitwarden/src/vault/sync.rs b/crates/bitwarden/src/vault/sync.rs index b303c0b2c..d751dbf6f 100644 --- a/crates/bitwarden/src/vault/sync.rs +++ b/crates/bitwarden/src/vault/sync.rs @@ -35,7 +35,7 @@ pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result