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-uniffi/src/auth/mod.rs b/crates/bitwarden-uniffi/src/auth/mod.rs index 1065a01a9..a70eebb8f 100644 --- a/crates/bitwarden-uniffi/src/auth/mod.rs +++ b/crates/bitwarden-uniffi/src/auth/mod.rs @@ -14,7 +14,7 @@ pub struct ClientAuth(pub(crate) Arc); #[uniffi::export(async_runtime = "tokio")] impl ClientAuth { /// **API Draft:** Calculate Password Strength - pub async fn password_strength( + pub fn password_strength( &self, password: String, email: String, @@ -22,14 +22,12 @@ impl ClientAuth { ) -> u8 { self.0 .0 - .write() - .await .auth() .password_strength(password, email, additional_inputs) } /// Evaluate if the provided password satisfies the provided policy - pub async fn satisfies_policy( + pub fn satisfies_policy( &self, password: String, strength: u8, @@ -37,8 +35,6 @@ impl ClientAuth { ) -> bool { self.0 .0 - .write() - .await .auth() .satisfies_policy(password, strength, &policy) } @@ -54,41 +50,33 @@ impl ClientAuth { Ok(self .0 .0 - .read() - .await .kdf() .hash_password(email, password, kdf_params, purpose) .await?) } /// Generate keys needed for registration process - pub async fn make_register_keys( + pub fn make_register_keys( &self, email: String, password: String, kdf: Kdf, ) -> Result { - Ok(self - .0 - .0 - .write() - .await - .auth() - .make_register_keys(email, password, kdf)?) + Ok(self.0 .0.auth().make_register_keys(email, password, kdf)?) } /// Generate keys needed for TDE process - pub async fn make_register_tde_keys( + pub fn make_register_tde_keys( &self, email: String, org_public_key: String, remember_device: bool, ) -> Result { - Ok(self.0 .0.write().await.auth().make_register_tde_keys( - email, - org_public_key, - remember_device, - )?) + Ok(self + .0 + .0 + .auth() + .make_register_tde_keys(email, org_public_key, remember_device)?) } /// Validate the user password @@ -96,12 +84,10 @@ impl ClientAuth { /// To retrieve the user's password hash, use [`ClientAuth::hash_password`] with /// `HashPurpose::LocalAuthentication` during login and persist it. If the login method has no /// password, use the email OTP. - pub async fn validate_password(&self, password: String, password_hash: String) -> Result { + pub fn validate_password(&self, password: String, password_hash: String) -> Result { Ok(self .0 .0 - .write() - .await .auth() .validate_password(password, password_hash)?) } @@ -112,7 +98,7 @@ impl ClientAuth { /// password. Some example are login with device or TDE. /// /// This works by comparing the provided password against the encrypted user key. - pub async fn validate_password_user_key( + pub fn validate_password_user_key( &self, password: String, encrypted_user_key: String, @@ -120,30 +106,22 @@ impl ClientAuth { Ok(self .0 .0 - .write() - .await .auth() .validate_password_user_key(password, encrypted_user_key)?) } /// Initialize a new auth request - pub async fn new_auth_request(&self, email: String) -> Result { - Ok(self.0 .0.write().await.auth().new_auth_request(&email)?) + pub fn new_auth_request(&self, email: String) -> Result { + Ok(self.0 .0.auth().new_auth_request(&email)?) } /// Approve an auth request - pub async fn approve_auth_request(&self, public_key: String) -> Result { - Ok(self - .0 - .0 - .write() - .await - .auth() - .approve_auth_request(public_key)?) + pub fn approve_auth_request(&self, public_key: String) -> Result { + Ok(self.0 .0.auth().approve_auth_request(public_key)?) } /// Trust the current device - pub async fn trust_device(&self) -> Result { - Ok(self.0 .0.write().await.auth().trust_device()?) + pub fn trust_device(&self) -> Result { + Ok(self.0 .0.auth().trust_device()?) } } diff --git a/crates/bitwarden-uniffi/src/crypto.rs b/crates/bitwarden-uniffi/src/crypto.rs index 991ff820f..761a72bc2 100644 --- a/crates/bitwarden-uniffi/src/crypto.rs +++ b/crates/bitwarden-uniffi/src/crypto.rs @@ -15,83 +15,41 @@ impl ClientCrypto { /// Initialization method for the user crypto. Needs to be called before any other crypto /// operations. pub async fn initialize_user_crypto(&self, req: InitUserCryptoRequest) -> Result<()> { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .initialize_user_crypto(req) - .await?) + Ok(self.0 .0.crypto().initialize_user_crypto(req).await?) } /// Initialization method for the organization crypto. Needs to be called after /// `initialize_user_crypto` but before any other crypto operations. pub async fn initialize_org_crypto(&self, req: InitOrgCryptoRequest) -> Result<()> { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .initialize_org_crypto(req) - .await?) + Ok(self.0 .0.crypto().initialize_org_crypto(req).await?) } /// Get the uses's decrypted encryption key. Note: It's very important /// to keep this key safe, as it can be used to decrypt all of the user's data pub async fn get_user_encryption_key(&self) -> Result { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .get_user_encryption_key() - .await?) + Ok(self.0 .0.crypto().get_user_encryption_key().await?) } /// Update the user's password, which will re-encrypt the user's encryption key with the new /// password. This returns the new encrypted user key and the new password hash. - pub async fn update_password(&self, new_password: String) -> Result { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .update_password(new_password)?) + pub fn update_password(&self, new_password: String) -> Result { + Ok(self.0 .0.crypto().update_password(new_password)?) } /// Generates a PIN protected user key from the provided PIN. The result can be stored and later /// used to initialize another client instance by using the PIN and the PIN key with /// `initialize_user_crypto`. - pub async fn derive_pin_key(&self, pin: String) -> Result { - Ok(self.0 .0.write().await.crypto().derive_pin_key(pin)?) + pub fn derive_pin_key(&self, pin: String) -> Result { + Ok(self.0 .0.crypto().derive_pin_key(pin)?) } /// Derives the pin protected user key from encrypted pin. Used when pin requires master /// password on first unlock. - pub async fn derive_pin_user_key(&self, encrypted_pin: EncString) -> Result { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .derive_pin_user_key(encrypted_pin)?) + pub fn derive_pin_user_key(&self, encrypted_pin: EncString) -> Result { + Ok(self.0 .0.crypto().derive_pin_user_key(encrypted_pin)?) } - pub async fn enroll_admin_password_reset( - &self, - public_key: String, - ) -> Result { - Ok(self - .0 - .0 - .write() - .await - .crypto() - .enroll_admin_password_reset(public_key)?) + pub fn enroll_admin_password_reset(&self, public_key: String) -> Result { + Ok(self.0 .0.crypto().enroll_admin_password_reset(public_key)?) } } diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index 318d47417..59f3e2035 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -2,7 +2,6 @@ uniffi::setup_scaffolding!(); use std::sync::Arc; -use async_lock::RwLock; use auth::ClientAuth; use bitwarden::client::client_settings::ClientSettings; @@ -24,7 +23,7 @@ use tool::{ClientExporters, ClientGenerators, ClientSends}; use vault::ClientVault; #[derive(uniffi::Object)] -pub struct Client(RwLock); +pub struct Client(bitwarden::Client); #[uniffi::export] impl Client { @@ -32,7 +31,7 @@ impl Client { #[uniffi::constructor] pub fn new(settings: Option) -> Arc { init_logger(); - Arc::new(Self(RwLock::new(bitwarden::Client::new(settings)))) + Arc::new(Self(bitwarden::Client::new(settings))) } /// Crypto operations diff --git a/crates/bitwarden-uniffi/src/platform/fido2.rs b/crates/bitwarden-uniffi/src/platform/fido2.rs index 3fc67f1d4..09162b7d0 100644 --- a/crates/bitwarden-uniffi/src/platform/fido2.rs +++ b/crates/bitwarden-uniffi/src/platform/fido2.rs @@ -57,10 +57,8 @@ impl ClientFido2Authenticator { &self, request: MakeCredentialRequest, ) -> Result { - let mut client = self.0 .0.write().await; - - let mut platform = client.platform(); - let mut fido2 = platform.fido2(); + let platform = self.0 .0.platform(); + let fido2 = platform.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -73,10 +71,8 @@ impl ClientFido2Authenticator { } pub async fn get_assertion(&self, request: GetAssertionRequest) -> Result { - let mut client = self.0 .0.write().await; - - let mut platform = client.platform(); - let mut fido2 = platform.fido2(); + let platform = self.0 .0.platform(); + let fido2 = platform.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -92,10 +88,8 @@ impl ClientFido2Authenticator { &self, rp_id: String, ) -> Result> { - let mut client = self.0 .0.write().await; - - let mut platform = client.platform(); - let mut fido2 = platform.fido2(); + let platform = self.0 .0.platform(); + let fido2 = platform.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -119,10 +113,8 @@ impl ClientFido2Client { request: String, client_data: ClientData, ) -> Result { - let mut client = self.0 .0 .0.write().await; - - let mut platform = client.platform(); - let mut fido2 = platform.fido2(); + let platform = self.0 .0 .0.platform(); + let fido2 = platform.fido2(); let ui = UniffiTraitBridge(self.0 .1.as_ref()); let cs = UniffiTraitBridge(self.0 .2.as_ref()); let mut client = fido2.create_client(&ui, &cs); @@ -140,10 +132,8 @@ impl ClientFido2Client { request: String, client_data: ClientData, ) -> Result { - let mut client = self.0 .0 .0.write().await; - - let mut platform = client.platform(); - let mut fido2 = platform.fido2(); + let platform = self.0 .0 .0.platform(); + let fido2 = platform.fido2(); let ui = UniffiTraitBridge(self.0 .1.as_ref()); let cs = UniffiTraitBridge(self.0 .2.as_ref()); let mut client = fido2.create_client(&ui, &cs); diff --git a/crates/bitwarden-uniffi/src/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index 458306676..fe7c401ee 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -9,34 +9,25 @@ mod fido2; #[derive(uniffi::Object)] pub struct ClientPlatform(pub(crate) Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientPlatform { /// Fingerprint (public key) - pub async fn fingerprint(&self, req: FingerprintRequest) -> Result { - Ok(self - .0 - .0 - .write() - .await - .platform() - .fingerprint(&req)? - .fingerprint) + pub fn fingerprint(&self, req: FingerprintRequest) -> Result { + Ok(self.0 .0.platform().fingerprint(&req)?.fingerprint) } /// Fingerprint using logged in user's public key - pub async fn user_fingerprint(&self, fingerprint_material: String) -> Result { + pub fn user_fingerprint(&self, fingerprint_material: String) -> Result { Ok(self .0 .0 - .write() - .await .platform() .user_fingerprint(fingerprint_material)?) } /// Load feature flags into the client - pub async fn load_flags(&self, flags: std::collections::HashMap) -> Result<()> { - self.0 .0.write().await.load_flags(flags); + pub fn load_flags(&self, flags: std::collections::HashMap) -> Result<()> { + self.0 .0.load_flags(flags); Ok(()) } diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index 78781b263..a590b41a3 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -17,35 +17,28 @@ pub struct ClientGenerators(pub(crate) Arc); #[uniffi::export(async_runtime = "tokio")] impl ClientGenerators { /// **API Draft:** Generate Password - pub async fn password(&self, settings: PasswordGeneratorRequest) -> Result { - Ok(self.0 .0.read().await.generator().password(settings)?) + pub fn password(&self, settings: PasswordGeneratorRequest) -> Result { + Ok(self.0 .0.generator().password(settings)?) } /// **API Draft:** Generate Passphrase - pub async fn passphrase(&self, settings: PassphraseGeneratorRequest) -> Result { - Ok(self.0 .0.read().await.generator().passphrase(settings)?) + pub fn passphrase(&self, settings: PassphraseGeneratorRequest) -> Result { + Ok(self.0 .0.generator().passphrase(settings)?) } /// **API Draft:** Generate Username pub async fn username(&self, settings: UsernameGeneratorRequest) -> Result { - Ok(self - .0 - .0 - .read() - .await - .generator() - .username(settings) - .await?) + Ok(self.0 .0.generator().username(settings).await?) } } #[derive(uniffi::Object)] pub struct ClientExporters(pub(crate) Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientExporters { /// **API Draft:** Export user vault - pub async fn export_vault( + pub fn export_vault( &self, folders: Vec, ciphers: Vec, @@ -54,14 +47,12 @@ impl ClientExporters { Ok(self .0 .0 - .read() - .await .exporters() .export_vault(folders, ciphers, format)?) } /// **API Draft:** Export organization vault - pub async fn export_organization_vault( + pub fn export_organization_vault( &self, collections: Vec, ciphers: Vec, @@ -70,8 +61,6 @@ impl ClientExporters { Ok(self .0 .0 - .read() - .await .exporters() .export_organization_vault(collections, ciphers, format)?) } diff --git a/crates/bitwarden-uniffi/src/tool/sends.rs b/crates/bitwarden-uniffi/src/tool/sends.rs index 36f174d38..ac9482429 100644 --- a/crates/bitwarden-uniffi/src/tool/sends.rs +++ b/crates/bitwarden-uniffi/src/tool/sends.rs @@ -7,32 +7,26 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientSends(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientSends { /// Encrypt send - pub async fn encrypt(&self, send: SendView) -> Result { - Ok(self.0 .0.write().await.sends().encrypt(send)?) + pub fn encrypt(&self, send: SendView) -> Result { + Ok(self.0 .0.sends().encrypt(send)?) } /// Encrypt a send file in memory - pub async fn encrypt_buffer(&self, send: Send, buffer: Vec) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .sends() - .encrypt_buffer(send, &buffer)?) + pub fn encrypt_buffer(&self, send: Send, buffer: Vec) -> Result> { + Ok(self.0 .0.sends().encrypt_buffer(send, &buffer)?) } /// Encrypt a send file located in the file system - pub async fn encrypt_file( + pub fn encrypt_file( &self, send: Send, decrypted_file_path: String, encrypted_file_path: String, ) -> Result<()> { - Ok(self.0 .0.write().await.sends().encrypt_file( + Ok(self.0 .0.sends().encrypt_file( send, Path::new(&decrypted_file_path), Path::new(&encrypted_file_path), @@ -40,34 +34,28 @@ impl ClientSends { } /// Decrypt send - pub async fn decrypt(&self, send: Send) -> Result { - Ok(self.0 .0.write().await.sends().decrypt(send)?) + pub fn decrypt(&self, send: Send) -> Result { + Ok(self.0 .0.sends().decrypt(send)?) } /// Decrypt send list - pub async fn decrypt_list(&self, sends: Vec) -> Result> { - Ok(self.0 .0.write().await.sends().decrypt_list(sends)?) + pub fn decrypt_list(&self, sends: Vec) -> Result> { + Ok(self.0 .0.sends().decrypt_list(sends)?) } /// Decrypt a send file in memory - pub async fn decrypt_buffer(&self, send: Send, buffer: Vec) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .sends() - .decrypt_buffer(send, &buffer)?) + pub fn decrypt_buffer(&self, send: Send, buffer: Vec) -> Result> { + Ok(self.0 .0.sends().decrypt_buffer(send, &buffer)?) } /// Decrypt a send file located in the file system - pub async fn decrypt_file( + pub fn decrypt_file( &self, send: Send, encrypted_file_path: String, decrypted_file_path: String, ) -> Result<()> { - Ok(self.0 .0.write().await.sends().decrypt_file( + Ok(self.0 .0.sends().decrypt_file( send, Path::new(&encrypted_file_path), Path::new(&decrypted_file_path), diff --git a/crates/bitwarden-uniffi/src/vault/attachments.rs b/crates/bitwarden-uniffi/src/vault/attachments.rs index bdac7c97c..0084029d2 100644 --- a/crates/bitwarden-uniffi/src/vault/attachments.rs +++ b/crates/bitwarden-uniffi/src/vault/attachments.rs @@ -7,10 +7,10 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientAttachments(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientAttachments { /// Encrypt an attachment file in memory - pub async fn encrypt_buffer( + pub fn encrypt_buffer( &self, cipher: Cipher, attachment: AttachmentView, @@ -19,22 +19,20 @@ impl ClientAttachments { Ok(self .0 .0 - .write() - .await .vault() .attachments() .encrypt_buffer(cipher, attachment, &buffer)?) } /// Encrypt an attachment file located in the file system - pub async fn encrypt_file( + pub fn encrypt_file( &self, cipher: Cipher, attachment: AttachmentView, decrypted_file_path: String, encrypted_file_path: String, ) -> Result { - Ok(self.0 .0.write().await.vault().attachments().encrypt_file( + Ok(self.0 .0.vault().attachments().encrypt_file( cipher, attachment, Path::new(&decrypted_file_path), @@ -42,7 +40,7 @@ impl ClientAttachments { )?) } /// Decrypt an attachment file in memory - pub async fn decrypt_buffer( + pub fn decrypt_buffer( &self, cipher: Cipher, attachment: Attachment, @@ -51,22 +49,20 @@ impl ClientAttachments { Ok(self .0 .0 - .write() - .await .vault() .attachments() .decrypt_buffer(cipher, attachment, &buffer)?) } /// Decrypt an attachment file located in the file system - pub async fn decrypt_file( + pub fn decrypt_file( &self, cipher: Cipher, attachment: Attachment, encrypted_file_path: String, decrypted_file_path: String, ) -> Result<()> { - Ok(self.0 .0.write().await.vault().attachments().decrypt_file( + Ok(self.0 .0.vault().attachments().decrypt_file( cipher, attachment, Path::new(&encrypted_file_path), diff --git a/crates/bitwarden-uniffi/src/vault/ciphers.rs b/crates/bitwarden-uniffi/src/vault/ciphers.rs index d637bc5fc..a8416434c 100644 --- a/crates/bitwarden-uniffi/src/vault/ciphers.rs +++ b/crates/bitwarden-uniffi/src/vault/ciphers.rs @@ -8,39 +8,25 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientCiphers(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientCiphers { /// Encrypt cipher - pub async fn encrypt(&self, cipher_view: CipherView) -> Result { - Ok(self - .0 - .0 - .write() - .await - .vault() - .ciphers() - .encrypt(cipher_view)?) + pub fn encrypt(&self, cipher_view: CipherView) -> Result { + Ok(self.0 .0.vault().ciphers().encrypt(cipher_view)?) } /// Decrypt cipher - pub async fn decrypt(&self, cipher: Cipher) -> Result { - Ok(self.0 .0.write().await.vault().ciphers().decrypt(cipher)?) + pub fn decrypt(&self, cipher: Cipher) -> Result { + Ok(self.0 .0.vault().ciphers().decrypt(cipher)?) } /// Decrypt cipher list - pub async fn decrypt_list(&self, ciphers: Vec) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .vault() - .ciphers() - .decrypt_list(ciphers)?) + pub fn decrypt_list(&self, ciphers: Vec) -> Result> { + Ok(self.0 .0.vault().ciphers().decrypt_list(ciphers)?) } /// Move a cipher to an organization, reencrypting the cipher key if necessary - pub async fn move_to_organization( + pub fn move_to_organization( &self, cipher: CipherView, organization_id: Uuid, @@ -48,8 +34,6 @@ impl ClientCiphers { Ok(self .0 .0 - .write() - .await .vault() .ciphers() .move_to_organization(cipher, organization_id)?) diff --git a/crates/bitwarden-uniffi/src/vault/collections.rs b/crates/bitwarden-uniffi/src/vault/collections.rs index f6cde84ab..47f84426b 100644 --- a/crates/bitwarden-uniffi/src/vault/collections.rs +++ b/crates/bitwarden-uniffi/src/vault/collections.rs @@ -7,29 +7,15 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientCollections(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientCollections { /// Decrypt collection - pub async fn decrypt(&self, collection: Collection) -> Result { - Ok(self - .0 - .0 - .write() - .await - .vault() - .collections() - .decrypt(collection)?) + pub fn decrypt(&self, collection: Collection) -> Result { + Ok(self.0 .0.vault().collections().decrypt(collection)?) } /// Decrypt collection list - pub async fn decrypt_list(&self, collections: Vec) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .vault() - .collections() - .decrypt_list(collections)?) + pub fn decrypt_list(&self, collections: Vec) -> Result> { + Ok(self.0 .0.vault().collections().decrypt_list(collections)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/folders.rs b/crates/bitwarden-uniffi/src/vault/folders.rs index 5cceeca8b..3fa5935b5 100644 --- a/crates/bitwarden-uniffi/src/vault/folders.rs +++ b/crates/bitwarden-uniffi/src/vault/folders.rs @@ -7,27 +7,20 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientFolders(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientFolders { /// Encrypt folder - pub async fn encrypt(&self, folder: FolderView) -> Result { - Ok(self.0 .0.write().await.vault().folders().encrypt(folder)?) + pub fn encrypt(&self, folder: FolderView) -> Result { + Ok(self.0 .0.vault().folders().encrypt(folder)?) } /// Decrypt folder - pub async fn decrypt(&self, folder: Folder) -> Result { - Ok(self.0 .0.write().await.vault().folders().decrypt(folder)?) + pub fn decrypt(&self, folder: Folder) -> Result { + Ok(self.0 .0.vault().folders().decrypt(folder)?) } /// Decrypt folder list - pub async fn decrypt_list(&self, folders: Vec) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .vault() - .folders() - .decrypt_list(folders)?) + pub fn decrypt_list(&self, folders: Vec) -> Result> { + Ok(self.0 .0.vault().folders().decrypt_list(folders)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/mod.rs b/crates/bitwarden-uniffi/src/vault/mod.rs index 62372523d..5259bc2bd 100644 --- a/crates/bitwarden-uniffi/src/vault/mod.rs +++ b/crates/bitwarden-uniffi/src/vault/mod.rs @@ -14,7 +14,7 @@ pub mod password_history; #[derive(uniffi::Object)] pub struct ClientVault(pub(crate) Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientVault { /// Folder operations pub fn folders(self: Arc) -> Arc { @@ -47,11 +47,7 @@ impl ClientVault { /// - A base32 encoded string /// - OTP Auth URI /// - Steam URI - pub async fn generate_totp( - &self, - key: String, - time: Option>, - ) -> Result { - Ok(self.0 .0.write().await.vault().generate_totp(key, time)?) + pub fn generate_totp(&self, key: String, time: Option>) -> Result { + Ok(self.0 .0.vault().generate_totp(key, time)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/password_history.rs b/crates/bitwarden-uniffi/src/vault/password_history.rs index 863eddbac..12ef993be 100644 --- a/crates/bitwarden-uniffi/src/vault/password_history.rs +++ b/crates/bitwarden-uniffi/src/vault/password_history.rs @@ -7,32 +7,20 @@ use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientPasswordHistory(pub Arc); -#[uniffi::export(async_runtime = "tokio")] +#[uniffi::export] impl ClientPasswordHistory { /// Encrypt password history - pub async fn encrypt(&self, password_history: PasswordHistoryView) -> Result { + pub fn encrypt(&self, password_history: PasswordHistoryView) -> Result { Ok(self .0 .0 - .write() - .await .vault() .password_history() .encrypt(password_history)?) } /// Decrypt password history - pub async fn decrypt_list( - &self, - list: Vec, - ) -> Result> { - Ok(self - .0 - .0 - .write() - .await - .vault() - .password_history() - .decrypt_list(list)?) + pub fn decrypt_list(&self, list: Vec) -> Result> { + Ok(self.0 .0.vault().password_history().decrypt_list(list)?) } } diff --git a/crates/bitwarden/src/auth/auth_request.rs b/crates/bitwarden/src/auth/auth_request.rs index c5ab6537e..7d90b6a36 100644 --- a/crates/bitwarden/src/auth/auth_request.rs +++ b/crates/bitwarden/src/auth/auth_request.rs @@ -84,7 +84,7 @@ pub(crate) fn auth_request_decrypt_master_key( /// /// Encrypts the user key with a public key. pub(crate) fn approve_auth_request( - client: &mut Client, + client: &Client, public_key: String, ) -> Result { let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(public_key)?)?; @@ -130,7 +130,7 @@ mod tests { #[test] fn test_approve() { - let mut client = Client::new(None); + let client = Client::new(None); let master_key = bitwarden_crypto::MasterKey::derive( "asdfasdfasdf".as_bytes(), @@ -154,7 +154,7 @@ mod tests { let fingerprint = fingerprint("test@bitwarden.com", &pbkey).unwrap(); assert_eq!(fingerprint, "childless-unfair-prowler-dropbox-designate"); - approve_auth_request(&mut client, public_key.to_owned()).unwrap(); + approve_auth_request(&client, public_key.to_owned()).unwrap(); } #[tokio::test] @@ -205,7 +205,7 @@ mod tests { let private_key = "2.yN7l00BOlUE0Sb0M//Q53w==|EwKG/BduQRQ33Izqc/ogoBROIoI5dmgrxSo82sgzgAMIBt3A2FZ9vPRMY+GWT85JiqytDitGR3TqwnFUBhKUpRRAq4x7rA6A1arHrFp5Tp1p21O3SfjtvB3quiOKbqWk6ZaU1Np9HwqwAecddFcB0YyBEiRX3VwF2pgpAdiPbSMuvo2qIgyob0CUoC/h4Bz1be7Qa7B0Xw9/fMKkB1LpOm925lzqosyMQM62YpMGkjMsbZz0uPopu32fxzDWSPr+kekNNyLt9InGhTpxLmq1go/pXR2uw5dfpXc5yuta7DB0EGBwnQ8Vl5HPdDooqOTD9I1jE0mRyuBpWTTI3FRnu3JUh3rIyGBJhUmHqGZvw2CKdqHCIrQeQkkEYqOeJRJVdBjhv5KGJifqT3BFRwX/YFJIChAQpebNQKXe/0kPivWokHWwXlDB7S7mBZzhaAPidZvnuIhalE2qmTypDwHy22FyqV58T8MGGMchcASDi/QXI6kcdpJzPXSeU9o+NC68QDlOIrMVxKFeE7w7PvVmAaxEo0YwmuAzzKy9QpdlK0aab/xEi8V4iXj4hGepqAvHkXIQd+r3FNeiLfllkb61p6WTjr5urcmDQMR94/wYoilpG5OlybHdbhsYHvIzYoLrC7fzl630gcO6t4nM24vdB6Ymg9BVpEgKRAxSbE62Tqacxqnz9AcmgItb48NiR/He3n3ydGjPYuKk/ihZMgEwAEZvSlNxYONSbYrIGDtOY+8Nbt6KiH3l06wjZW8tcmFeVlWv+tWotnTY9IqlAfvNVTjtsobqtQnvsiDjdEVtNy/s2ci5TH+NdZluca2OVEr91Wayxh70kpM6ib4UGbfdmGgCo74gtKvKSJU0rTHakQ5L9JlaSDD5FamBRyI0qfL43Ad9qOUZ8DaffDCyuaVyuqk7cz9HwmEmvWU3VQ+5t06n/5kRDXttcw8w+3qClEEdGo1KeENcnXCB32dQe3tDTFpuAIMLqwXs6FhpawfZ5kPYvLPczGWaqftIs/RXJ/EltGc0ugw2dmTLpoQhCqrcKEBDoYVk0LDZKsnzitOGdi9mOWse7Se8798ib1UsHFUjGzISEt6upestxOeupSTOh0v4+AjXbDzRUyogHww3V+Bqg71bkcMxtB+WM+pn1XNbVTyl9NR040nhP7KEf6e9ruXAtmrBC2ah5cFEpLIot77VFZ9ilLuitSz+7T8n1yAh1IEG6xxXxninAZIzi2qGbH69O5RSpOJuJTv17zTLJQIIc781JwQ2TTwTGnx5wZLbffhCasowJKd2EVcyMJyhz6ru0PvXWJ4hUdkARJs3Xu8dus9a86N8Xk6aAPzBDqzYb1vyFIfBxP0oO8xFHgd30Cgmz8UrSE3qeWRrF8ftrI6xQnFjHBGWD/JWSvd6YMcQED0aVuQkuNW9ST/DzQThPzRfPUoiL10yAmV7Ytu4fR3x2sF0Yfi87YhHFuCMpV/DsqxmUizyiJuD938eRcH8hzR/VO53Qo3UIsqOLcyXtTv6THjSlTopQ+JOLOnHm1w8dzYbLN44OG44rRsbihMUQp+wUZ6bsI8rrOnm9WErzkbQFbrfAINdoCiNa6cimYIjvvnMTaFWNymqY1vZxGztQiMiHiHYwTfwHTXrb9j0uPM=|09J28iXv9oWzYtzK2LBT6Yht4IT4MijEkk0fwFdrVQ4="; // Initialize an existing client which is unlocked - let mut existing_device = Client::new(None); + let existing_device = Client::new(None); let master_key = bitwarden_crypto::MasterKey::derive("asdfasdfasdf".as_bytes(), email.as_bytes(), &kdf) @@ -216,11 +216,11 @@ mod tests { .unwrap(); // Initialize a new device which will request to be logged in - let mut new_device = Client::new(None); + let new_device = Client::new(None); // Initialize an auth request, and approve it on the existing device let auth_req = new_auth_request(email).unwrap(); - let approved_req = approve_auth_request(&mut existing_device, auth_req.public_key).unwrap(); + let approved_req = approve_auth_request(&existing_device, auth_req.public_key).unwrap(); // Unlock the vault using the approved request new_device diff --git a/crates/bitwarden/src/auth/client_auth.rs b/crates/bitwarden/src/auth/client_auth.rs index 14261efee..32b429047 100644 --- a/crates/bitwarden/src/auth/client_auth.rs +++ b/crates/bitwarden/src/auth/client_auth.rs @@ -27,17 +27,17 @@ use crate::{ }; pub struct ClientAuth<'a> { - pub(crate) client: &'a mut crate::Client, + pub(crate) client: &'a crate::Client, } impl<'a> ClientAuth<'a> { - pub async fn renew_token(&mut self) -> Result<()> { + pub async fn renew_token(&self) -> Result<()> { renew_token(self.client).await } #[cfg(feature = "secrets")] pub async fn login_access_token( - &mut self, + &self, input: &AccessTokenLoginRequest, ) -> Result { login_access_token(self.client, input).await @@ -74,7 +74,7 @@ impl<'a> ClientAuth<'a> { } pub fn make_register_tde_keys( - &mut self, + &self, email: String, org_public_key: String, remember_device: bool, @@ -82,11 +82,11 @@ impl<'a> ClientAuth<'a> { make_register_tde_keys(self.client, email, org_public_key, remember_device) } - pub async fn register(&mut self, input: &RegisterRequest) -> Result<()> { + pub async fn register(&self, input: &RegisterRequest) -> Result<()> { register(self.client, input).await } - pub async fn prelogin(&mut self, email: String) -> Result { + pub async fn prelogin(&self, email: String) -> Result { use crate::auth::login::{parse_prelogin, request_prelogin}; let response = request_prelogin(self.client, email).await?; @@ -94,20 +94,17 @@ impl<'a> ClientAuth<'a> { } pub async fn login_password( - &mut self, + &self, input: &PasswordLoginRequest, ) -> Result { login_password(self.client, input).await } - pub async fn login_api_key( - &mut self, - input: &ApiKeyLoginRequest, - ) -> Result { + pub async fn login_api_key(&self, input: &ApiKeyLoginRequest) -> Result { login_api_key(self.client, input).await } - pub async fn send_two_factor_email(&mut self, tf: &TwoFactorEmailRequest) -> Result<()> { + pub async fn send_two_factor_email(&self, tf: &TwoFactorEmailRequest) -> Result<()> { send_two_factor_email(self.client, tf).await } @@ -127,7 +124,7 @@ impl<'a> ClientAuth<'a> { new_auth_request(email) } - pub fn approve_auth_request(&mut self, public_key: String) -> Result { + pub fn approve_auth_request(&self, public_key: String) -> Result { approve_auth_request(self.client, public_key) } @@ -139,7 +136,7 @@ impl<'a> ClientAuth<'a> { #[cfg(feature = "internal")] impl<'a> ClientAuth<'a> { pub async fn login_device( - &mut self, + &self, email: String, device_identifier: String, ) -> Result { @@ -148,7 +145,7 @@ impl<'a> ClientAuth<'a> { send_new_auth_request(self.client, email, device_identifier).await } - pub async fn login_device_complete(&mut self, auth_req: NewAuthRequestResponse) -> Result<()> { + pub async fn login_device_complete(&self, auth_req: NewAuthRequestResponse) -> Result<()> { use crate::auth::login::complete_auth_request; complete_auth_request(self.client, auth_req).await @@ -167,7 +164,7 @@ fn trust_device(client: &Client) -> Result { } impl<'a> Client { - pub fn auth(&'a mut self) -> ClientAuth<'a> { + pub fn auth(&'a self) -> ClientAuth<'a> { ClientAuth { client: self } } } diff --git a/crates/bitwarden/src/auth/login/access_token.rs b/crates/bitwarden/src/auth/login/access_token.rs index a376eb0c3..25d8ffb5d 100644 --- a/crates/bitwarden/src/auth/login/access_token.rs +++ b/crates/bitwarden/src/auth/login/access_token.rs @@ -21,7 +21,7 @@ use crate::{ }; pub(crate) async fn login_access_token( - client: &mut Client, + client: &Client, input: &AccessTokenLoginRequest, ) -> Result { //info!("api key logging in"); @@ -99,17 +99,17 @@ pub(crate) async fn login_access_token( } async fn request_access_token( - client: &mut Client, + client: &Client, input: &AccessToken, ) -> Result { let config = client.get_api_configurations().await; AccessTokenRequest::new(input.access_token_id, &input.client_secret) - .send(config) + .send(&config) .await } fn load_tokens_from_state( - client: &mut Client, + client: &Client, state_file: &Path, access_token: &AccessToken, ) -> Result { diff --git a/crates/bitwarden/src/auth/login/api_key.rs b/crates/bitwarden/src/auth/login/api_key.rs index 3882931ba..92f1c76b9 100644 --- a/crates/bitwarden/src/auth/login/api_key.rs +++ b/crates/bitwarden/src/auth/login/api_key.rs @@ -15,7 +15,7 @@ use crate::{ }; pub(crate) async fn login_api_key( - client: &mut Client, + client: &Client, input: &ApiKeyLoginRequest, ) -> Result { //info!("api key logging in"); @@ -58,12 +58,12 @@ pub(crate) async fn login_api_key( } async fn request_api_identity_tokens( - client: &mut Client, + client: &Client, input: &ApiKeyLoginRequest, ) -> 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 6a8005b6d..380a49b9d 100644 --- a/crates/bitwarden/src/auth/login/auth_request.rs +++ b/crates/bitwarden/src/auth/login/auth_request.rs @@ -27,7 +27,7 @@ pub struct NewAuthRequestResponse { } pub(crate) async fn send_new_auth_request( - client: &mut Client, + client: &Client, email: String, device_identifier: String, ) -> Result { @@ -56,7 +56,7 @@ pub(crate) async fn send_new_auth_request( } pub(crate) async fn complete_auth_request( - client: &mut Client, + client: &Client, auth_req: NewAuthRequestResponse, ) -> Result<()> { let config = client.get_api_configurations().await; @@ -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/mod.rs b/crates/bitwarden/src/auth/login/mod.rs index 7fac112f5..9c9c711b9 100644 --- a/crates/bitwarden/src/auth/login/mod.rs +++ b/crates/bitwarden/src/auth/login/mod.rs @@ -45,7 +45,7 @@ pub use access_token::{AccessTokenLoginRequest, AccessTokenLoginResponse}; #[cfg(feature = "internal")] pub(crate) async fn request_prelogin( - client: &mut Client, + client: &Client, email: String, ) -> Result { let request_model = PreloginRequestModel::new(email); diff --git a/crates/bitwarden/src/auth/login/password.rs b/crates/bitwarden/src/auth/login/password.rs index 4960b498b..bbbae3d1a 100644 --- a/crates/bitwarden/src/auth/login/password.rs +++ b/crates/bitwarden/src/auth/login/password.rs @@ -19,7 +19,7 @@ use crate::{ #[cfg(feature = "internal")] pub(crate) async fn login_password( - client: &mut Client, + client: &Client, input: &PasswordLoginRequest, ) -> Result { use bitwarden_core::require; @@ -62,7 +62,7 @@ pub(crate) async fn login_password( #[cfg(feature = "internal")] async fn request_identity_tokens( - client: &mut Client, + client: &Client, input: &PasswordLoginRequest, password_hash: &str, ) -> Result { @@ -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/login/two_factor.rs b/crates/bitwarden/src/auth/login/two_factor.rs index c8f0cc55b..197ff77a1 100644 --- a/crates/bitwarden/src/auth/login/two_factor.rs +++ b/crates/bitwarden/src/auth/login/two_factor.rs @@ -16,7 +16,7 @@ pub struct TwoFactorEmailRequest { } pub(crate) async fn send_two_factor_email( - client: &mut Client, + client: &Client, input: &TwoFactorEmailRequest, ) -> Result<()> { // TODO: This should be resolved from the client diff --git a/crates/bitwarden/src/auth/password/validate.rs b/crates/bitwarden/src/auth/password/validate.rs index 5502ecc55..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, .. } => { @@ -86,7 +80,7 @@ mod tests { use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; - let mut client = Client::new(None); + let client = Client::new(None); client.set_login_method(LoginMethod::User(UserLoginMethod::Username { email: "test@bitwarden.com".to_string(), kdf: Kdf::PBKDF2 { @@ -110,7 +104,7 @@ mod tests { use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; - let mut client = Client::new(None); + let client = Client::new(None); let password = "asdfasdfasdf"; let email = "test@bitwarden.com"; @@ -150,7 +144,7 @@ mod tests { use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; - let mut client = Client::new(None); + let client = Client::new(None); let password = b"asdfasdfasdf"; let email = "test@bitwarden.com"; diff --git a/crates/bitwarden/src/auth/register.rs b/crates/bitwarden/src/auth/register.rs index 06313d42b..5ca995ead 100644 --- a/crates/bitwarden/src/auth/register.rs +++ b/crates/bitwarden/src/auth/register.rs @@ -18,7 +18,7 @@ pub struct RegisterRequest { } /// Half baked implementation of user registration -pub(super) async fn register(client: &mut Client, req: &RegisterRequest) -> Result<()> { +pub(super) async fn register(client: &Client, req: &RegisterRequest) -> Result<()> { let config = client.get_api_configurations().await; let kdf = Kdf::default(); diff --git a/crates/bitwarden/src/auth/renew.rs b/crates/bitwarden/src/auth/renew.rs index 783494ae2..01108cf2c 100644 --- a/crates/bitwarden/src/auth/renew.rs +++ b/crates/bitwarden/src/auth/renew.rs @@ -9,29 +9,40 @@ use crate::{ secrets_manager::state::{self, ClientState}, }; -pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { +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 tokens = client + .tokens + .read() + .expect("RwLock is not poisoned") + .clone(); + let login_method = client + .login_method + .read() + .expect("RwLock is not poisoned") + .clone(); + + if let (Some(expires), Some(login_method)) = (tokens.expires_on, 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() - .ok_or(Error::NotAuthenticated)?; + let refresh = tokens.refresh_token.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 +50,7 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { .. } => { ApiTokenRequest::new(client_id, client_secret) - .send(&client.__api_configurations) + .send(&config) .await? } }, @@ -53,7 +64,7 @@ pub(crate) async fn renew_token(client: &mut 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/auth/tde.rs b/crates/bitwarden/src/auth/tde.rs index 02f36583c..e1ddb0921 100644 --- a/crates/bitwarden/src/auth/tde.rs +++ b/crates/bitwarden/src/auth/tde.rs @@ -10,7 +10,7 @@ use crate::{error::Result, Client}; /// generated user key, and encrypts the user key with the organization public key for admin /// password reset. If remember_device is true, it also generates a device key. pub(super) fn make_register_tde_keys( - client: &mut Client, + client: &Client, email: String, org_public_key: String, remember_device: bool, diff --git a/crates/bitwarden/src/client/client.rs b/crates/bitwarden/src/client/client.rs index 0d2f30864..31e32f034 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, } @@ -66,23 +66,37 @@ pub(crate) enum ServiceAccountLoginMethod { }, } +#[derive(Debug, Default, Clone)] +pub(crate) struct Tokens { + // These two fields are always written to, but they are not read + // from the secrets manager SDK. + #[cfg_attr(not(feature = "internal"), allow(dead_code))] + access_token: Option, + pub(crate) expires_on: Option, + + #[cfg_attr(not(feature = "internal"), allow(dead_code))] + pub(crate) refresh_token: Option, +} + /// 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, + pub(crate) tokens: 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>, - encryption_settings: Option, + /// Reqwest client useable for external integrations like email forwarders, HIBP. + #[allow(unused)] + pub(crate) external_client: reqwest::Client, + + encryption_settings: RwLock>>, } impl Client { @@ -135,144 +149,192 @@ impl Client { }; Self { - token: None, - refresh_token: None, - token_expires_on: None, - login_method: None, + tokens: RwLock::new(Tokens::default()), + 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(&mut self, flags: std::collections::HashMap) { - self.flags = Flags::load_from_map(flags); + pub fn load_flags(&self, flags: std::collections::HashMap) { + *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(&mut 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, VaultLocked> { - self.encryption_settings.as_ref().ok_or(VaultLocked) + pub(crate) fn get_encryption_settings(&self) -> Result, VaultLocked> { + self.encryption_settings + .read() + .expect("RwLock is not poisoned") + .clone() + .ok_or(VaultLocked) } - pub(crate) fn set_login_method(&mut self, login_method: LoginMethod) { + 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( - &mut 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); + pub(crate) fn set_tokens(&self, token: String, refresh_token: Option, expires_in: u64) { + *self.tokens.write().expect("RwLock is not poisoned") = Tokens { + access_token: Some(token.clone()), + expires_on: Some(Utc::now().timestamp() + expires_in as i64), + refresh_token, + }; + 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() + let is_token_set = self + .tokens + .read() + .expect("RwLock is not poisoned") + .access_token + .is_some(); + let is_login_method_set = self + .login_method + .read() + .expect("RwLock is not poisoned") + .is_some(); + + is_token_set || is_login_method_set } #[cfg(feature = "internal")] pub(crate) fn initialize_user_crypto_master_key( - &mut self, + &self, 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")] pub(crate) fn initialize_user_crypto_decrypted_key( - &mut self, + &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")] pub(crate) fn initialize_user_crypto_pin( - &mut self, + &self, 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( - &mut 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( - &mut self, + &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/client/test_accounts.rs b/crates/bitwarden/src/client/test_accounts.rs index 22927d7d8..7c24df0ac 100644 --- a/crates/bitwarden/src/client/test_accounts.rs +++ b/crates/bitwarden/src/client/test_accounts.rs @@ -12,19 +12,17 @@ use crate::{ impl Client { pub async fn init_test_account(account: TestAccount) -> Self { - let mut client = Client::new(None); + let client = Client::new(None); client.load_flags(HashMap::from([( "enableCipherKeyEncryption".to_owned(), true, )])); - initialize_user_crypto(&mut client, account.user) - .await - .unwrap(); + initialize_user_crypto(&client, account.user).await.unwrap(); if let Some(org) = account.org { - initialize_org_crypto(&mut client, org).await.unwrap(); + initialize_org_crypto(&client, org).await.unwrap(); } client diff --git a/crates/bitwarden/src/mobile/client_crypto.rs b/crates/bitwarden/src/mobile/client_crypto.rs index 30e88332a..88e359844 100644 --- a/crates/bitwarden/src/mobile/client_crypto.rs +++ b/crates/bitwarden/src/mobile/client_crypto.rs @@ -13,51 +13,48 @@ use crate::{ }; pub struct ClientCrypto<'a> { - pub(crate) client: &'a mut crate::Client, + pub(crate) client: &'a crate::Client, } impl<'a> ClientCrypto<'a> { #[cfg(feature = "internal")] - pub async fn initialize_user_crypto(&mut self, req: InitUserCryptoRequest) -> Result<()> { + pub async fn initialize_user_crypto(&self, req: InitUserCryptoRequest) -> Result<()> { initialize_user_crypto(self.client, req).await } #[cfg(feature = "internal")] - pub async fn initialize_org_crypto(&mut self, req: InitOrgCryptoRequest) -> Result<()> { + pub async fn initialize_org_crypto(&self, req: InitOrgCryptoRequest) -> Result<()> { initialize_org_crypto(self.client, req).await } #[cfg(feature = "internal")] - pub async fn get_user_encryption_key(&mut self) -> Result { + pub async fn get_user_encryption_key(&self) -> Result { get_user_encryption_key(self.client).await } #[cfg(feature = "internal")] - pub fn update_password(&mut self, new_password: String) -> Result { + pub fn update_password(&self, new_password: String) -> Result { update_password(self.client, new_password) } #[cfg(feature = "internal")] - pub fn derive_pin_key(&mut self, pin: String) -> Result { + pub fn derive_pin_key(&self, pin: String) -> Result { derive_pin_key(self.client, pin) } #[cfg(feature = "internal")] - pub fn derive_pin_user_key(&mut self, encrypted_pin: EncString) -> Result { + pub fn derive_pin_user_key(&self, encrypted_pin: EncString) -> Result { derive_pin_user_key(self.client, encrypted_pin) } #[cfg(feature = "internal")] - pub fn enroll_admin_password_reset( - &mut self, - public_key: String, - ) -> Result { + pub fn enroll_admin_password_reset(&self, public_key: String) -> Result { enroll_admin_password_reset(self.client, public_key) } } impl<'a> Client { - pub fn crypto(&'a mut self) -> ClientCrypto<'a> { + pub fn crypto(&'a self) -> ClientCrypto<'a> { ClientCrypto { client: self } } } diff --git a/crates/bitwarden/src/mobile/crypto.rs b/crates/bitwarden/src/mobile/crypto.rs index ea5a70cce..fde041e5f 100644 --- a/crates/bitwarden/src/mobile/crypto.rs +++ b/crates/bitwarden/src/mobile/crypto.rs @@ -86,7 +86,7 @@ pub enum AuthRequestMethod { } #[cfg(feature = "internal")] -pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequest) -> Result<()> { +pub async fn initialize_user_crypto(client: &Client, req: InitUserCryptoRequest) -> Result<()> { use bitwarden_crypto::DeviceKey; use crate::auth::{auth_request_decrypt_master_key, auth_request_decrypt_user_key}; @@ -165,18 +165,16 @@ pub struct InitOrgCryptoRequest { } #[cfg(feature = "internal")] -pub async fn initialize_org_crypto(client: &mut Client, req: InitOrgCryptoRequest) -> Result<()> { +pub async fn initialize_org_crypto(client: &Client, req: InitOrgCryptoRequest) -> Result<()> { let organization_keys = req.organization_keys.into_iter().collect(); client.initialize_org_crypto(organization_keys)?; Ok(()) } #[cfg(feature = "internal")] -pub async fn get_user_encryption_key(client: &mut Client) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; +pub async fn get_user_encryption_key(client: &Client) -> Result { + let enc = client.get_encryption_settings()?; + let user_key = enc.get_key(&None).ok_or(VaultLocked)?; Ok(user_key.to_base64()) } @@ -192,22 +190,14 @@ pub struct UpdatePasswordResponse { new_key: EncString, } -pub fn update_password( - client: &mut Client, - new_password: String, -) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; +pub fn update_password(client: &Client, new_password: String) -> Result { + 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, .. }, @@ -240,18 +230,13 @@ pub struct DerivePinKeyResponse { } #[cfg(feature = "internal")] -pub fn derive_pin_key(client: &mut Client, pin: String) -> Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; +pub fn derive_pin_key(client: &Client, pin: String) -> Result { + 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, @@ -260,19 +245,14 @@ pub fn derive_pin_key(client: &mut Client, pin: String) -> Result Result { - let user_key = client - .get_encryption_settings()? - .get_key(&None) - .ok_or(VaultLocked)?; +pub fn derive_pin_user_key(client: &Client, encrypted_pin: EncString) -> Result { + 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")] @@ -294,7 +274,7 @@ fn derive_pin_protected_user_key( #[cfg(feature = "internal")] pub(super) fn enroll_admin_password_reset( - client: &mut Client, + client: &Client, public_key: String, ) -> Result { use base64::{engine::general_purpose::STANDARD, Engine}; @@ -317,7 +297,7 @@ mod tests { #[tokio::test] async fn test_update_password() { - let mut client = Client::new(None); + let client = Client::new(None); let priv_key = "2.kmLY8NJVuiKBFJtNd/ZFpA==|qOodlRXER+9ogCe3yOibRHmUcSNvjSKhdDuztLlucs10jLiNoVVVAc+9KfNErLSpx5wmUF1hBOJM8zwVPjgQTrmnNf/wuDpwiaCxNYb/0v4FygPy7ccAHK94xP1lfqq7U9+tv+/yiZSwgcT+xF0wFpoxQeNdNRFzPTuD9o4134n8bzacD9DV/WjcrXfRjbBCzzuUGj1e78+A7BWN7/5IWLz87KWk8G7O/W4+8PtEzlwkru6Wd1xO19GYU18oArCWCNoegSmcGn7w7NDEXlwD403oY8Oa7ylnbqGE28PVJx+HLPNIdSC6YKXeIOMnVs7Mctd/wXC93zGxAWD6ooTCzHSPVV50zKJmWIG2cVVUS7j35H3rGDtUHLI+ASXMEux9REZB8CdVOZMzp2wYeiOpggebJy6MKOZqPT1R3X0fqF2dHtRFPXrNsVr1Qt6bS9qTyO4ag1/BCvXF3P1uJEsI812BFAne3cYHy5bIOxuozPfipJrTb5WH35bxhElqwT3y/o/6JWOGg3HLDun31YmiZ2HScAsUAcEkA4hhoTNnqy4O2s3yVbCcR7jF7NLsbQc0MDTbnjxTdI4VnqUIn8s2c9hIJy/j80pmO9Bjxp+LQ9a2hUkfHgFhgHxZUVaeGVth8zG2kkgGdrp5VHhxMVFfvB26Ka6q6qE/UcS2lONSv+4T8niVRJz57qwctj8MNOkA3PTEfe/DP/LKMefke31YfT0xogHsLhDkx+mS8FCc01HReTjKLktk/Jh9mXwC5oKwueWWwlxI935ecn+3I2kAuOfMsgPLkoEBlwgiREC1pM7VVX1x8WmzIQVQTHd4iwnX96QewYckGRfNYWz/zwvWnjWlfcg8kRSe+68EHOGeRtC5r27fWLqRc0HNcjwpgHkI/b6czerCe8+07TWql4keJxJxhBYj3iOH7r9ZS8ck51XnOb8tGL1isimAJXodYGzakwktqHAD7MZhS+P02O+6jrg7d+yPC2ZCuS/3TOplYOCHQIhnZtR87PXTUwr83zfOwAwCyv6KP84JUQ45+DItrXLap7nOVZKQ5QxYIlbThAO6eima6Zu5XHfqGPMNWv0bLf5+vAjIa5np5DJrSwz9no/hj6CUh0iyI+SJq4RGI60lKtypMvF6MR3nHLEHOycRUQbZIyTHWl4QQLdHzuwN9lv10ouTEvNr6sFflAX2yb6w3hlCo7oBytH3rJekjb3IIOzBpeTPIejxzVlh0N9OT5MZdh4sNKYHUoWJ8mnfjdM+L4j5Q2Kgk/XiGDgEebkUxiEOQUdVpePF5uSCE+TPav/9FIRGXGiFn6NJMaU7aBsDTFBLloffFLYDpd8/bTwoSvifkj7buwLYM+h/qcnfdy5FWau1cKav+Blq/ZC0qBpo658RTC8ZtseAFDgXoQZuksM10hpP9bzD04Bx30xTGX81QbaSTNwSEEVrOtIhbDrj9OI43KH4O6zLzK+t30QxAv5zjk10RZ4+5SAdYndIlld9Y62opCfPDzRy3ubdve4ZEchpIKWTQvIxq3T5ogOhGaWBVYnkMtM2GVqvWV//46gET5SH/MdcwhACUcZ9kCpMnWH9CyyUwYvTT3UlNyV+DlS27LMPvaw7tx7qa+GfNCoCBd8S4esZpQYK/WReiS8=|pc7qpD42wxyXemdNPuwxbh8iIaryrBPu8f/DGwYdHTw="; @@ -326,7 +306,7 @@ mod tests { }; initialize_user_crypto( - &mut client, + & client, InitUserCryptoRequest { kdf_params: kdf.clone(), email: "test@bitwarden.com".into(), @@ -340,12 +320,12 @@ mod tests { .await .unwrap(); - let new_password_response = update_password(&mut client, "123412341234".into()).unwrap(); + let new_password_response = update_password(&client, "123412341234".into()).unwrap(); - let mut client2 = Client::new(None); + let client2 = Client::new(None); initialize_user_crypto( - &mut client2, + &client2, InitUserCryptoRequest { kdf_params: kdf.clone(), email: "test@bitwarden.com".into(), @@ -390,12 +370,12 @@ mod tests { #[tokio::test] async fn test_initialize_user_crypto_pin() { - let mut client = Client::new(None); + let client = Client::new(None); let priv_key = "2.kmLY8NJVuiKBFJtNd/ZFpA==|qOodlRXER+9ogCe3yOibRHmUcSNvjSKhdDuztLlucs10jLiNoVVVAc+9KfNErLSpx5wmUF1hBOJM8zwVPjgQTrmnNf/wuDpwiaCxNYb/0v4FygPy7ccAHK94xP1lfqq7U9+tv+/yiZSwgcT+xF0wFpoxQeNdNRFzPTuD9o4134n8bzacD9DV/WjcrXfRjbBCzzuUGj1e78+A7BWN7/5IWLz87KWk8G7O/W4+8PtEzlwkru6Wd1xO19GYU18oArCWCNoegSmcGn7w7NDEXlwD403oY8Oa7ylnbqGE28PVJx+HLPNIdSC6YKXeIOMnVs7Mctd/wXC93zGxAWD6ooTCzHSPVV50zKJmWIG2cVVUS7j35H3rGDtUHLI+ASXMEux9REZB8CdVOZMzp2wYeiOpggebJy6MKOZqPT1R3X0fqF2dHtRFPXrNsVr1Qt6bS9qTyO4ag1/BCvXF3P1uJEsI812BFAne3cYHy5bIOxuozPfipJrTb5WH35bxhElqwT3y/o/6JWOGg3HLDun31YmiZ2HScAsUAcEkA4hhoTNnqy4O2s3yVbCcR7jF7NLsbQc0MDTbnjxTdI4VnqUIn8s2c9hIJy/j80pmO9Bjxp+LQ9a2hUkfHgFhgHxZUVaeGVth8zG2kkgGdrp5VHhxMVFfvB26Ka6q6qE/UcS2lONSv+4T8niVRJz57qwctj8MNOkA3PTEfe/DP/LKMefke31YfT0xogHsLhDkx+mS8FCc01HReTjKLktk/Jh9mXwC5oKwueWWwlxI935ecn+3I2kAuOfMsgPLkoEBlwgiREC1pM7VVX1x8WmzIQVQTHd4iwnX96QewYckGRfNYWz/zwvWnjWlfcg8kRSe+68EHOGeRtC5r27fWLqRc0HNcjwpgHkI/b6czerCe8+07TWql4keJxJxhBYj3iOH7r9ZS8ck51XnOb8tGL1isimAJXodYGzakwktqHAD7MZhS+P02O+6jrg7d+yPC2ZCuS/3TOplYOCHQIhnZtR87PXTUwr83zfOwAwCyv6KP84JUQ45+DItrXLap7nOVZKQ5QxYIlbThAO6eima6Zu5XHfqGPMNWv0bLf5+vAjIa5np5DJrSwz9no/hj6CUh0iyI+SJq4RGI60lKtypMvF6MR3nHLEHOycRUQbZIyTHWl4QQLdHzuwN9lv10ouTEvNr6sFflAX2yb6w3hlCo7oBytH3rJekjb3IIOzBpeTPIejxzVlh0N9OT5MZdh4sNKYHUoWJ8mnfjdM+L4j5Q2Kgk/XiGDgEebkUxiEOQUdVpePF5uSCE+TPav/9FIRGXGiFn6NJMaU7aBsDTFBLloffFLYDpd8/bTwoSvifkj7buwLYM+h/qcnfdy5FWau1cKav+Blq/ZC0qBpo658RTC8ZtseAFDgXoQZuksM10hpP9bzD04Bx30xTGX81QbaSTNwSEEVrOtIhbDrj9OI43KH4O6zLzK+t30QxAv5zjk10RZ4+5SAdYndIlld9Y62opCfPDzRy3ubdve4ZEchpIKWTQvIxq3T5ogOhGaWBVYnkMtM2GVqvWV//46gET5SH/MdcwhACUcZ9kCpMnWH9CyyUwYvTT3UlNyV+DlS27LMPvaw7tx7qa+GfNCoCBd8S4esZpQYK/WReiS8=|pc7qpD42wxyXemdNPuwxbh8iIaryrBPu8f/DGwYdHTw="; initialize_user_crypto( - &mut client, + & client, InitUserCryptoRequest { kdf_params: Kdf::PBKDF2 { iterations: 100_000.try_into().unwrap(), @@ -411,12 +391,12 @@ mod tests { .await .unwrap(); - let pin_key = derive_pin_key(&mut client, "1234".into()).unwrap(); + let pin_key = derive_pin_key(&client, "1234".into()).unwrap(); // Verify we can unlock with the pin - let mut client2 = Client::new(None); + let client2 = Client::new(None); initialize_user_crypto( - &mut client2, + &client2, InitUserCryptoRequest { kdf_params: Kdf::PBKDF2 { iterations: 100_000.try_into().unwrap(), @@ -448,13 +428,12 @@ mod tests { ); // Verify we can derive the pin protected user key from the encrypted pin - let pin_protected_user_key = - derive_pin_user_key(&mut client, pin_key.encrypted_pin).unwrap(); + let pin_protected_user_key = derive_pin_user_key(&client, pin_key.encrypted_pin).unwrap(); - let mut client3 = Client::new(None); + let client3 = Client::new(None); initialize_user_crypto( - &mut client3, + &client3, InitUserCryptoRequest { kdf_params: Kdf::PBKDF2 { iterations: 100_000.try_into().unwrap(), @@ -494,7 +473,7 @@ mod tests { use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_crypto::AsymmetricCryptoKey; - let mut client = Client::new(None); + let client = Client::new(None); let master_key = bitwarden_crypto::MasterKey::derive( "asdfasdfasdf".as_bytes(), @@ -513,18 +492,15 @@ mod tests { let public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsy7RFHcX3C8Q4/OMmhhbFReYWfB45W9PDTEA8tUZwZmtOiN2RErIS2M1c+K/4HoDJ/TjpbX1f2MZcr4nWvKFuqnZXyewFc+jmvKVewYi+NAu2++vqKq2kKcmMNhwoQDQdQIVy/Uqlp4Cpi2cIwO6ogq5nHNJGR3jm+CpyrafYlbz1bPvL3hbyoGDuG2tgADhyhXUdFuef2oF3wMvn1lAJAvJnPYpMiXUFmj1ejmbwtlxZDrHgUJvUcp7nYdwUKaFoi+sOttHn3u7eZPtNvxMjhSS/X/1xBIzP/mKNLdywH5LoRxniokUk+fV3PYUxJsiU3lV0Trc/tH46jqd8ZGjmwIDAQAB"; - let encrypted = enroll_admin_password_reset(&mut client, public_key.to_owned()).unwrap(); + let encrypted = enroll_admin_password_reset(&client, public_key.to_owned()).unwrap(); let private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzLtEUdxfcLxDj84yaGFsVF5hZ8Hjlb08NMQDy1RnBma06I3ZESshLYzVz4r/gegMn9OOltfV/Yxlyvida8oW6qdlfJ7AVz6Oa8pV7BiL40C7b76+oqraQpyYw2HChANB1AhXL9SqWngKmLZwjA7qiCrmcc0kZHeOb4KnKtp9iVvPVs+8veFvKgYO4ba2AAOHKFdR0W55/agXfAy+fWUAkC8mc9ikyJdQWaPV6OZvC2XFkOseBQm9Rynudh3BQpoWiL6w620efe7t5k+02/EyOFJL9f/XEEjM/+Yo0t3LAfkuhHGeKiRST59Xc9hTEmyJTeVXROtz+0fjqOp3xkaObAgMBAAECggEACs4xhnO0HaZhh1/iH7zORMIRXKeyxP2LQiTR8xwN5JJ9wRWmGAR9VasS7EZFTDidIGVME2u/h4s5EqXnhxfO+0gGksVvgNXJ/qw87E8K2216g6ZNo6vSGA7H1GH2voWwejJ4/k/cJug6dz2S402rRAKh2Wong1arYHSkVlQp3diiMa5FHAOSE+Cy09O2ZsaF9IXQYUtlW6AVXFrBEPYH2kvkaPXchh8VETMijo6tbvoKLnUHe+wTaDMls7hy8exjtVyI59r3DNzjy1lNGaGb5QSnFMXR+eHhPZc844Wv02MxC15zKABADrl58gpJyjTl6XpDdHCYGsmGpVGH3X9TQQKBgQDz/9beFjzq59ve6rGwn+EtnQfSsyYT+jr7GN8lNEXb3YOFXBgPhfFIcHRh2R00Vm9w2ApfAx2cd8xm2I6HuvQ1Os7g26LWazvuWY0Qzb+KaCLQTEGH1RnTq6CCG+BTRq/a3J8M4t38GV5TWlzv8wr9U4dl6FR4efjb65HXs1GQ4QKBgQC7/uHfrOTEHrLeIeqEuSl0vWNqEotFKdKLV6xpOvNuxDGbgW4/r/zaxDqt0YBOXmRbQYSEhmO3oy9J6XfE1SUln0gbavZeW0HESCAmUIC88bDnspUwS9RxauqT5aF8ODKN/bNCWCnBM1xyonPOs1oT1nyparJVdQoG//Y7vkB3+wKBgBqLqPq8fKAp3XfhHLfUjREDVoiLyQa/YI9U42IOz9LdxKNLo6p8rgVthpvmnRDGnpUuS+KOWjhdqDVANjF6G3t3DG7WNl8Rh5Gk2H4NhFswfSkgQrjebFLlBy9gjQVCWXt8KSmjvPbiY6q52Aaa8IUjA0YJAregvXxfopxO+/7BAoGARicvEtDp7WWnSc1OPoj6N14VIxgYcI7SyrzE0d/1x3ffKzB5e7qomNpxKzvqrVP8DzG7ydh8jaKPmv1MfF8tpYRy3AhmN3/GYwCnPqT75YYrhcrWcVdax5gmQVqHkFtIQkRSCIftzPLlpMGKha/YBV8c1fvC4LD0NPh/Ynv0gtECgYEAyOZg95/kte0jpgUEgwuMrzkhY/AaUJULFuR5MkyvReEbtSBQwV5tx60+T95PHNiFooWWVXiLMsAgyI2IbkxVR1Pzdri3gWK5CTfqb7kLuaj/B7SGvBa2Sxo478KS5K8tBBBWkITqo+wLC0mn3uZi1dyMWO1zopTA+KtEGF2dtGQ="; let private_key = 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 9feeec030..38a7d072d 100644 --- a/crates/bitwarden/src/mobile/tool/client_sends.rs +++ b/crates/bitwarden/src/mobile/tool/client_sends.rs @@ -75,20 +75,17 @@ impl<'a> ClientSends<'a> { } pub 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)?; - Ok(enc.to_buffer()?) + let encrypted = buffer.encrypt_with_key(&key)?; + Ok(encrypted.to_buffer()?) } } impl<'a> Client { - pub fn sends(&'a mut self) -> ClientSends<'a> { + pub fn sends(&'a self) -> ClientSends<'a> { ClientSends { client: self } } } diff --git a/crates/bitwarden/src/mobile/vault/client_attachments.rs b/crates/bitwarden/src/mobile/vault/client_attachments.rs index 2f9edb82b..4140a4d88 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 e459f4e7c..bbbb01652 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 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) } } @@ -80,7 +80,7 @@ mod tests { #[tokio::test] async fn test_decrypt_list() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let dec = client .vault() @@ -181,7 +181,7 @@ mod tests { #[tokio::test] async fn test_move_user_cipher_with_attachment_without_key_to_org_fails() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let mut cipher = test_cipher(); cipher.attachments = Some(vec![test_attachment_legacy()]); @@ -199,7 +199,7 @@ mod tests { #[tokio::test] async fn test_encrypt_cipher_with_legacy_attachment_without_key() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let mut cipher = test_cipher(); let attachment = test_attachment_legacy(); @@ -238,7 +238,7 @@ mod tests { #[tokio::test] async fn test_encrypt_cipher_with_v1_attachment_without_key() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let mut cipher = test_cipher(); let attachment = test_attachment_v2(); diff --git a/crates/bitwarden/src/mobile/vault/client_collection.rs b/crates/bitwarden/src/mobile/vault/client_collection.rs index 0727130df..09f1f3c6a 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 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(); @@ -50,7 +50,7 @@ mod tests { #[tokio::test] async fn test_decrypt_list() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let dec = client.vault().collections().decrypt_list(vec![Collection { id: Some("66c5ca57-0868-4c7e-902f-b181009709c0".parse().unwrap()), @@ -66,7 +66,7 @@ mod tests { #[tokio::test] async fn test_decrypt() { - let mut client = Client::init_test_account(test_bitwarden_com_account()).await; + let client = Client::init_test_account(test_bitwarden_com_account()).await; let dec = client.vault().collections().decrypt(Collection { id: Some("66c5ca57-0868-4c7e-902f-b181009709c0".parse().unwrap()), diff --git a/crates/bitwarden/src/platform/client_platform.rs b/crates/bitwarden/src/platform/client_platform.rs index 733a86e72..945011393 100644 --- a/crates/bitwarden/src/platform/client_platform.rs +++ b/crates/bitwarden/src/platform/client_platform.rs @@ -8,7 +8,7 @@ use super::{ use crate::{error::Result, Client}; pub struct ClientPlatform<'a> { - pub(crate) client: &'a mut Client, + pub(crate) client: &'a Client, } impl<'a> ClientPlatform<'a> { @@ -28,7 +28,7 @@ impl<'a> ClientPlatform<'a> { } #[cfg(feature = "uniffi")] - pub fn fido2(&'a mut self) -> ClientFido2<'a> { + pub fn fido2(&'a self) -> ClientFido2<'a> { ClientFido2 { client: self.client, } @@ -36,7 +36,7 @@ impl<'a> ClientPlatform<'a> { } impl<'a> Client { - pub fn platform(&'a mut self) -> ClientPlatform<'a> { + pub fn platform(&'a self) -> ClientPlatform<'a> { ClientPlatform { client: self } } } diff --git a/crates/bitwarden/src/platform/fido2/authenticator.rs b/crates/bitwarden/src/platform/fido2/authenticator.rs index 825e4f6d8..d0a7b83e4 100644 --- a/crates/bitwarden/src/platform/fido2/authenticator.rs +++ b/crates/bitwarden/src/platform/fido2/authenticator.rs @@ -77,7 +77,7 @@ pub enum SilentlyDiscoverCredentialsError { } pub struct Fido2Authenticator<'a> { - pub(crate) client: &'a mut Client, + pub(crate) client: &'a Client, pub(crate) user_interface: &'a dyn Fido2UserInterface, pub(crate) credential_store: &'a dyn Fido2CredentialStore, @@ -225,7 +225,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()) } @@ -268,7 +268,7 @@ impl<'a> Fido2Authenticator<'a> { .clone() .ok_or(GetSelectedCredentialError::NoSelectedCredential)?; - let creds = cipher.decrypt_fido2_credentials(enc)?; + let creds = cipher.decrypt_fido2_credentials(&enc)?; let credential = creds .first() @@ -339,7 +339,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { if this.create_credential { Ok(creds .into_iter() - .map(|c| CipherViewContainer::new(c, enc)) + .map(|c| CipherViewContainer::new(c, &enc)) .collect::>()?) } else { let picked = this @@ -355,7 +355,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)?]) } } @@ -411,7 +411,7 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { .clone() .ok_or(InnerError::NoSelectedCredential)?; - 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 @@ -481,7 +481,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/fido2/mod.rs b/crates/bitwarden/src/platform/fido2/mod.rs index 3f08b8810..da9d19a65 100644 --- a/crates/bitwarden/src/platform/fido2/mod.rs +++ b/crates/bitwarden/src/platform/fido2/mod.rs @@ -43,12 +43,12 @@ const AAGUID: Aaguid = Aaguid([ pub struct ClientFido2<'a> { #[allow(dead_code)] - pub(crate) client: &'a mut Client, + pub(crate) client: &'a Client, } impl<'a> ClientFido2<'a> { pub fn create_authenticator( - &'a mut self, + &'a self, user_interface: &'a dyn Fido2UserInterface, credential_store: &'a dyn Fido2CredentialStore, ) -> Fido2Authenticator<'a> { @@ -62,7 +62,7 @@ impl<'a> ClientFido2<'a> { } pub fn create_client( - &'a mut self, + &'a self, user_interface: &'a dyn Fido2UserInterface, credential_store: &'a dyn Fido2CredentialStore, ) -> Fido2Client<'a> { diff --git a/crates/bitwarden/src/platform/generate_fingerprint.rs b/crates/bitwarden/src/platform/generate_fingerprint.rs index d62eb5436..521a75c01 100644 --- a/crates/bitwarden/src/platform/generate_fingerprint.rs +++ b/crates/bitwarden/src/platform/generate_fingerprint.rs @@ -33,7 +33,7 @@ pub(crate) fn generate_fingerprint(input: &FingerprintRequest) -> Result Result { info!("Generating fingerprint"); @@ -63,7 +63,7 @@ mod tests { let private_key = "2.tY6WsWKUbBwNU8wROuipiQ==|DNFL1d19xVojUKTTy2gxT+9J1VXbMQLcbMnx1HSeA6U3yZhsLR6DPaGibb3Bp8doIHtrsxzL/JeLb4gLDZ8RnDhFfE4iLRaPakX14kbBXrKH9/uW/zc7TqIVciWhI1PaeFlu8wnVuGt3e5Ysx6Y7Uw7RS8pRT5aE3sX3aDPGZTAdTutLn1VUfkShS5OK5HJl9CdiwV2wOcrf4w/WqtaNUUqGdsJ8C4ELlpBzHxqs+lEm+8pGPYmuGQIjVc0eOR9Tza9GTk3ih1XGc1znOCoKUZbtA29RfbwfmJy/yGi/3RLWZFQGCCij4cLC5OpldiX4JWL5Dhox44p/5IVF3rfxTVz3GCyDOoHevRG/06sUBq6nhbdCQf3lJvxwcQJhoQg4rsapM3rgol+u+TbXRiwWPbfswuLkRlvGFKtKUWMa4S57gj0CFYgSBPdTyhZTB44D7JQ2bd901Ur1dYWcDe4Kn3ZawpxL0cX2ZPlE3v8FXFJf2s8DJytL8yu73GasDzVmaGHxueWWVz7EHjh+pmB4oaAHARcY8d3LActAyl/+bcFRPYQJ68ae6DJhYYJGHIBWMImf2BifGgUX8vUFfUAYjne3D82lRyZQHs3xbl+ZxEPgWiPYRWUtxGXLLP4f9mbl+LeJdehtHNjC8kOduBL0CsP4gmugzNNUXI+Izc/9svno6kFr6SU0LA3MGrOU8ao7UCQbf/Pj/RKnG1gRmBDQqf7IMm6jOyTwdde9NpfQb32iH11PkuAKBvEtUuq9BeAKWjoZku+ycsN2jZH0hzd/QrU2c+E4+yHwX3wSxxorNOXt5EZkJbEDBlpRyE1zWoyy0wIYfcChYLvFN8QFHchlw5wmHxL+OOgdgndAtV/2DCx+NB6caY31qLictME+1GPPlQ7QvicMLgmpSWq83rs4ex/My6p3hCRSrJJiLvjEDZLYWKHHLd5tsPRAjX8ADNWB1VeIeiJrj1wpOCc1PbWpbljbbTsBmVPo6iKm/UDGAHBdQ//0j3FQg8f5w/j+McsoaMpDNHNTiLvjWERR+RBmsEA0lEL00wZz/DHlzOAYHLYYqFMT7GBCQD+Wk/l1TL+X2agUy7Irlk7QbZ4ivfdNIpSW8Ct9MGE6o4wV+nIpXURojgBBTcP85RTBLXXGrIprnK1G/VE8ONag3+nkqIyChjYyk5QMsxqOqSHsbiOxhCdXypbCbY4g9yKJtBJ/ADjxmELj0X7pqsTFqC0eRT7rk9qTBcYBBu6rwlAfq8AKjDB7WjNjzLaMi6lBoe4petBn1xcLkXD5hHra0TULxcYrq8MIb+Vk4CBZZdwwyVm/28SwSjHBIBpRysPAonDDsp3KlahwXEFvRDQR/oFww172GI7cx8SoPn93Qh0JfpTAAowsO3meR8bzUSyd7v3rmtaBPsWHE9zUXye/6nloMU5joEcD6uJaxd0kdaWWIoKLH++zHW1R776wJrS6u+TIWZgHqiIJoCd9fV25BnQcbZRKd6mnfNQkchJ6c6ozXKrFaa8DLdERdfh84+isw5mzW2zMJwHEwtKt6LUTyieC2exzPAwPxJT1+IMjuzuwiLnvGKOq+kwE/LWBSB0ZfGuCP/3jMM8OCfe7Hbpt1TfXcUxUzj6sSjkjQB6qBt+TINRdOFA=|fppguME86utsAOKrBYn6XU95q7daVbZ+3dD9OVkQlAw="; let fingerprint_material = "a09726a0-9590-49d1-a5f5-afe300b6a515"; - let mut client = Client::new(None); + let client = Client::new(None); let master_key = bitwarden_crypto::MasterKey::derive( "asdfasdfasdf".as_bytes(), @@ -83,7 +83,7 @@ mod tests { .unwrap(); let fingerprint = - generate_user_fingerprint(&mut client, fingerprint_material.to_string()).unwrap(); + generate_user_fingerprint(&client, fingerprint_material.to_string()).unwrap(); assert_eq!(fingerprint, "turban-deftly-anime-chatroom-unselfish"); } diff --git a/crates/bitwarden/src/platform/get_user_api_key.rs b/crates/bitwarden/src/platform/get_user_api_key.rs index 207721f44..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}, @@ -16,14 +18,14 @@ use crate::{ }; pub(crate) async fn get_user_api_key( - client: &mut Client, + client: &Client, input: &SecretVerificationRequest, ) -> Result { info!("Getting 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..fc5a3b5ae 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)?; @@ -38,7 +38,5 @@ pub(crate) async fn create_project( ) .await?; - 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..55cd69757 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)?; @@ -37,7 +37,5 @@ pub(crate) async fn update_project( bitwarden_api_api::apis::projects_api::projects_id_put(&config.api, input.id, project) .await?; - 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..51c8b28a9 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)?; @@ -46,7 +46,5 @@ pub(crate) async fn create_secret( ) .await?; - 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..58665eac9 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)?; @@ -42,7 +42,5 @@ pub(crate) async fn update_secret( let res = bitwarden_api_api::apis::secrets_api::secrets_id_put(&config.api, input.id, secret).await?; - 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 321ed5f6c..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, @@ -87,7 +84,7 @@ mod tests { #[test] fn test_convert_format() { - let mut client = Client::new(None); + let client = Client::new(None); client.set_login_method(LoginMethod::User(UserLoginMethod::Username { client_id: "7b821276-e27c-400b-9853-606393c87f18".to_owned(), email: "test@bitwarden.com".to_owned(), diff --git a/crates/bitwarden/src/vault/client_vault.rs b/crates/bitwarden/src/vault/client_vault.rs index 550947ed5..49ba5edd7 100644 --- a/crates/bitwarden/src/vault/client_vault.rs +++ b/crates/bitwarden/src/vault/client_vault.rs @@ -2,17 +2,17 @@ use super::sync::{sync, SyncRequest, SyncResponse}; use crate::{error::Result, Client}; pub struct ClientVault<'a> { - pub(crate) client: &'a mut crate::Client, + pub(crate) client: &'a crate::Client, } impl<'a> ClientVault<'a> { - pub async fn sync(&mut self, input: &SyncRequest) -> Result { + pub async fn sync(&self, input: &SyncRequest) -> Result { sync(self.client, input).await } } impl<'a> Client { - pub fn vault(&'a mut self) -> ClientVault<'a> { + pub fn vault(&'a self) -> ClientVault<'a> { ClientVault { client: self } } } diff --git a/crates/bitwarden/src/vault/sync.rs b/crates/bitwarden/src/vault/sync.rs index b7b96d63f..d751dbf6f 100644 --- a/crates/bitwarden/src/vault/sync.rs +++ b/crates/bitwarden/src/vault/sync.rs @@ -20,7 +20,7 @@ pub struct SyncRequest { pub exclude_subdomains: Option, } -pub(crate) async fn sync(client: &mut Client, input: &SyncRequest) -> Result { +pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result { let config = client.get_api_configurations().await; let sync = bitwarden_api_api::apis::sync_api::sync_get(&config.api, input.exclude_subdomains).await?; @@ -35,7 +35,7 @@ pub(crate) async fn sync(client: &mut Client, input: &SyncRequest) -> Result) -> Result<()> { +pub(crate) async fn login_password(client: Client, email: Option) -> Result<()> { let email = text_prompt_when_none("Email", email)?; let password = Password::new("Password").without_confirmation().prompt()?; @@ -93,7 +93,7 @@ pub(crate) async fn login_password(mut client: Client, email: Option) -> } pub(crate) async fn login_api_key( - mut client: Client, + client: Client, client_id: Option, client_secret: Option, ) -> Result<()> { @@ -117,7 +117,7 @@ pub(crate) async fn login_api_key( } pub(crate) async fn login_device( - mut client: Client, + client: Client, email: Option, device_identifier: Option, ) -> Result<()> { diff --git a/crates/bw/src/main.rs b/crates/bw/src/main.rs index 6a1918126..c8af014f0 100644 --- a/crates/bw/src/main.rs +++ b/crates/bw/src/main.rs @@ -188,7 +188,7 @@ async fn process_commands() -> Result<()> { identity_url: format!("{}/identity", server), ..Default::default() }); - let mut client = bitwarden::Client::new(settings); + let client = bitwarden::Client::new(settings); let email = text_prompt_when_none("Email", email)?; let password = Password::new("Password").prompt()?;