Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ crates/bitwarden-vault/** @bitwarden/team-vault-dev
# Team-owned folders in other crates (to be avoided if possible)
crates/bitwarden-wasm-internal/integration-tests/tests/organizations/** @bitwarden/team-admin-console-dev
crates/bitwarden-wasm-internal/integration-tests/tests/unlock/** @bitwarden/team-key-management-dev
crates/bitwarden-wasm-internal/integration-tests/tests/user-crypto-management/** @bitwarden/team-key-management-dev
crates/bitwarden-wasm-internal/src/pure_crypto.rs @bitwarden/team-key-management-dev
crates/bitwarden-core/src/key_management/** @bitwarden/team-key-management-dev @bitwarden/team-platform-dev
crates/bitwarden-ipc/src/crypto_provider/noise/ @bitwarden/team-key-management-dev
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 21 additions & 1 deletion crates/bitwarden-core/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub struct ClientBuilder {
token_handler: Arc<dyn TokenHandler>,
state_registry: Option<StateRegistry>,
middleware: Vec<Arc<dyn reqwest_middleware::Middleware>>,
#[cfg(feature = "test-fixtures")]
api_configurations: Option<Arc<ApiConfigurations>>,
}

impl ClientBuilder {
Expand All @@ -34,9 +36,20 @@ impl ClientBuilder {
token_handler: Arc::new(NoopTokenHandler),
state_registry: None,
middleware: Vec::new(),
#[cfg(feature = "test-fixtures")]
api_configurations: None,
}
}

/// Overrides the [`ApiConfigurations`] used by the client being built, allowing tests to inject
/// a mocked [`bitwarden_api_api::apis::ApiClient`] via
/// [`ApiConfigurations::from_api_client`]. Only available for testing.
#[cfg(feature = "test-fixtures")]
pub fn with_api_configurations(mut self, api_configurations: Arc<ApiConfigurations>) -> Self {
self.api_configurations = Some(api_configurations);
self
}

/// Sets the [`ClientSettings`] for the client being built.
pub fn with_settings(mut self, settings: ClientSettings) -> Self {
self.settings = Some(settings);
Expand Down Expand Up @@ -132,11 +145,18 @@ impl ClientBuilder {
client: bw_http_client,
};

#[cfg(feature = "test-fixtures")]
let api_configurations = self
.api_configurations
.unwrap_or_else(|| ApiConfigurations::new(identity, api, settings.device_type));
#[cfg(not(feature = "test-fixtures"))]
let api_configurations = ApiConfigurations::new(identity, api, settings.device_type);

let client = Client {
internal: Arc::new(InternalClient {
user_id: OnceLock::new(),
token_handler: self.token_handler,
api_configurations: ApiConfigurations::new(identity, api, settings.device_type),
api_configurations,
external_http_client,
key_store,
#[cfg(feature = "internal")]
Expand Down
28 changes: 26 additions & 2 deletions crates/bitwarden-core/src/client/test_accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use bitwarden_test::MemoryRepository;
#[cfg(feature = "test-fixtures")]
use crate::{
Client, ClientSettings, UserId,
client::ApiConfigurations,
key_management::{
LocalUserDataKeyState, MasterPasswordUnlockData, UserKeyState,
account_cryptographic_state::WrappedAccountCryptographicState,
Expand All @@ -22,7 +23,11 @@ impl Client {
/// Creates a client with the necessary state repositories for testing.
/// Does not initialize any crypto state.
pub fn new_test(settings: Option<ClientSettings>) -> Self {
let client = Client::new(settings);
Self::register_test_repositories(Client::new(settings))
}

/// Registers the state repositories required by the test-account crypto initialization.
fn register_test_repositories(client: Client) -> Self {
client
.platform()
.state()
Expand All @@ -40,8 +45,27 @@ impl Client {
}

pub async fn init_test_account(account: TestAccount) -> Self {
let client = Client::new_test(None);
Self::init_test_account_on(Client::new_test(None), account).await
}

/// Creates a test account client backed by a mocked
/// [`bitwarden_api_api::apis::ApiClient`], so tests can assert on API requests made by
/// sub-clients that operate on a full [`Client`].
pub async fn init_test_account_with_api_client(
account: TestAccount,
api_client: bitwarden_api_api::apis::ApiClient,
) -> Self {
let client = Self::register_test_repositories(
Client::builder()
.with_api_configurations(std::sync::Arc::new(ApiConfigurations::from_api_client(
api_client,
)))
.build(),
);
Self::init_test_account_on(client, account).await
}

async fn init_test_account_on(client: Client, account: TestAccount) -> Self {
client
.flags()
.load(HashMap::from([(
Expand Down
3 changes: 3 additions & 0 deletions crates/bitwarden-core/src/key_management/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ pub(super) async fn get_user_encryption_key(client: &Client) -> Result<B64, Cryp
}

/// Response from the `update_kdf` function
///
/// Note: This is deprecated and will be removed after key-connector fully uses sdk
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
Expand All @@ -484,6 +486,7 @@ pub struct UpdateKdfResponse {
old_master_password_authentication_data: MasterPasswordAuthenticationData,
}

// Note: This is deprecated and will be removed after key-connector fully uses sdk
pub(super) async fn make_update_kdf(
client: &Client,
password: &str,
Expand Down
2 changes: 2 additions & 0 deletions crates/bitwarden-core/src/key_management/crypto_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ impl CryptoClient {
/// Create the data necessary to update the user's kdf settings. The user's encryption key is
/// re-encrypted for the password under the new kdf settings. This returns the re-encrypted
/// user key and the new password hash but does not update sdk state.
///
/// Note: This is deprecated. Please use the user-crypto-management client instead.
pub async fn make_update_kdf(
&self,
password: String,
Expand Down
3 changes: 2 additions & 1 deletion crates/bitwarden-core/src/key_management/state_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use std::sync::{Arc, Mutex};

use bitwarden_crypto::{EncString, SymmetricCryptoKey, safe::PasswordProtectedKeyEnvelope};
use bitwarden_crypto::{EncString, Kdf, SymmetricCryptoKey, safe::PasswordProtectedKeyEnvelope};
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

Expand Down Expand Up @@ -148,4 +148,5 @@ bitwarden_state_bridge_macro::state_bridge! {
v2_upgrade_token: V2UpgradeToken as ts "V2UpgradeToken",
account_cryptographic_state: WrappedAccountCryptographicState as ts "WrappedAccountCryptographicState",
masterpassword_unlock_data: MasterPasswordUnlockData as ts "MasterPasswordUnlockData",
kdf_config: Kdf as ts "Kdf",
}
8 changes: 7 additions & 1 deletion crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ uniffi = [
"dep:bitwarden-uniffi-error",
"dep:uniffi",
] # Uniffi bindings
wasm = ["dep:tsify", "dep:wasm-bindgen", "dep:js-sys"] # WASM support
wasm = [
"dep:tsify",
"dep:wasm-bindgen",
"dep:js-sys",
"dep:serde-wasm-bindgen",
] # WASM support
# WARNING: This feature is for debugging purposes only and should never be enabled in production.
# It disables compile-time debug prevention for cryptographic keys, exposing sensitive key material
# in debug output, and adds tracing debug logs to encrypt/decrypt operations.
Expand Down Expand Up @@ -63,6 +68,7 @@ rayon = ">=1.8.1, <2.0"
rsa = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
serde-wasm-bindgen = { workspace = true, optional = true }
serde_bytes = { workspace = true }
serde_repr.workspace = true
sha1 = { workspace = true, features = ["zeroize"] }
Expand Down
9 changes: 9 additions & 0 deletions crates/bitwarden-crypto/src/keys/kdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ pub enum Kdf {
},
}

#[cfg(feature = "wasm")]
impl TryFrom<wasm_bindgen::JsValue> for Kdf {
type Error = serde_wasm_bindgen::Error;

fn try_from(value: wasm_bindgen::JsValue) -> Result<Self, Self::Error> {
serde_wasm_bindgen::from_value(value)
}
}

impl Kdf {
/// Default KDF for new encryption V1 accounts.
pub fn default_pbkdf2() -> Kdf {
Expand Down
2 changes: 2 additions & 0 deletions crates/bitwarden-uniffi/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ impl CryptoClient {
/// Create the data necessary to update the user's kdf settings. The user's encryption key is
/// re-encrypted for the password under the new kdf settings. This returns the new encrypted
/// user key and the new password hash but does not update sdk state.
/// Note: This is deprecated. Please use the user-crypto-management client instead.
pub async fn make_update_kdf(&self, password: String, kdf: Kdf) -> Result<UpdateKdfResponse> {
#[allow(deprecated)]
Ok(self.0.make_update_kdf(password, kdf).await?)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ actor InMemoryStateBridge: StateBridgeForeignImpl {
private var v2UpgradeToken: V2UpgradeToken?
private var accountCryptographicState: WrappedAccountCryptographicState?
private var masterpasswordUnlockData: MasterPasswordUnlockData?
private var kdfConfig: Kdf?

func setUserKey(value: SymmetricCryptoKey) { userKey = value }
func getUserKey() -> SymmetricCryptoKey? { userKey }
Expand Down Expand Up @@ -90,6 +91,10 @@ actor InMemoryStateBridge: StateBridgeForeignImpl {
func setMasterpasswordUnlockData(value: MasterPasswordUnlockData) { masterpasswordUnlockData = value }
func getMasterpasswordUnlockData() -> MasterPasswordUnlockData? { masterpasswordUnlockData }
func clearMasterpasswordUnlockData() { masterpasswordUnlockData = nil }

func setKdfConfig(value: Kdf) { kdfConfig = value }
func getKdfConfig() -> Kdf? { kdfConfig }
func clearKdfConfig() { kdfConfig = nil }
}

final class MockTokenProvider: ClientManagedTokens {
Expand Down
5 changes: 4 additions & 1 deletion crates/bitwarden-user-crypto-management/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ wasm-bindgen-futures = { workspace = true, optional = true }

[dev-dependencies]
bitwarden-api-api = { workspace = true, features = ["mockall"] }
bitwarden-core = { workspace = true, features = ["internal-test-utils"] }
bitwarden-core = { workspace = true, features = [
"internal-test-utils",
"test-fixtures",
] }
bitwarden-test = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["rt"] }
Expand Down
Loading
Loading