From 17c99577b37455c79773a1fd0158e08da78c0418 Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 24 May 2024 12:28:31 +0200 Subject: [PATCH 01/28] Rename `bitwarden` crate to `bitwarden-core` --- Cargo.lock | 62 +++++++++++-------- Cargo.toml | 2 +- .../CHANGELOG.md | 0 .../{bitwarden => bitwarden-core}/Cargo.toml | 2 +- .../{bitwarden => bitwarden-core}/README.md | 0 .../src/.gitignore | 0 .../src/admin_console/mod.rs | 0 .../src/admin_console/policy.rs | 0 .../src/auth/access_token.rs | 0 .../src/auth/api/mod.rs | 0 .../auth/api/request/access_token_request.rs | 0 .../src/auth/api/request/api_token_request.rs | 0 .../api/request/auth_request_token_request.rs | 0 .../src/auth/api/request/mod.rs | 0 .../api/request/password_token_request.rs | 0 .../auth/api/request/renew_token_request.rs | 0 .../api/response/identity_captcha_response.rs | 0 .../api/response/identity_payload_response.rs | 0 .../api/response/identity_refresh_response.rs | 0 .../api/response/identity_success_response.rs | 0 .../response/identity_token_fail_response.rs | 0 .../api/response/identity_token_response.rs | 0 .../response/identity_two_factor_response.rs | 0 .../src/auth/api/response/mod.rs | 0 .../two_factor_provider_data/authenticator.rs | 0 .../response/two_factor_provider_data/duo.rs | 0 .../two_factor_provider_data/email.rs | 0 .../response/two_factor_provider_data/mod.rs | 0 .../organization_duo.rs | 0 .../two_factor_provider_data/remember.rs | 0 .../two_factor_provider_data/web_authn.rs | 0 .../two_factor_provider_data/yubi_key.rs | 0 .../auth/api/response/two_factor_providers.rs | 0 .../src/auth/auth_request.rs | 0 .../src/auth/client_auth.rs | 0 .../src/auth/jwt_token.rs | 0 .../src/auth/login/access_token.rs | 0 .../src/auth/login/api_key.rs | 0 .../src/auth/login/auth_request.rs | 0 .../src/auth/login/mod.rs | 0 .../src/auth/login/password.rs | 0 .../auth/login/response/captcha_response.rs | 0 .../src/auth/login/response/mod.rs | 0 .../response/two_factor/authenticator.rs | 0 .../src/auth/login/response/two_factor/duo.rs | 0 .../auth/login/response/two_factor/email.rs | 0 .../src/auth/login/response/two_factor/mod.rs | 0 .../login/response/two_factor/remember.rs | 0 .../two_factor/two_factor_providers.rs | 0 .../login/response/two_factor/web_authn.rs | 0 .../login/response/two_factor/yubi_key.rs | 0 .../src/auth/login/two_factor.rs | 0 .../src/auth/mod.rs | 0 .../src/auth/password/mod.rs | 0 .../src/auth/password/policy.rs | 0 .../src/auth/password/strength.rs | 0 .../src/auth/password/validate.rs | 0 .../src/auth/register.rs | 0 .../src/auth/renew.rs | 0 .../src/auth/tde.rs | 0 .../src/client/client.rs | 0 .../src/client/client_settings.rs | 0 .../src/client/encryption_settings.rs | 0 .../src/client/flags.rs | 0 .../src/client/mod.rs | 0 .../src/error.rs | 0 .../{bitwarden => bitwarden-core}/src/lib.rs | 0 .../src/mobile/client_crypto.rs | 0 .../src/mobile/client_kdf.rs | 0 .../src/mobile/crypto.rs | 0 .../src/mobile/kdf.rs | 0 .../src/mobile/mod.rs | 0 .../src/mobile/vault/client_attachments.rs | 0 .../src/mobile/vault/client_ciphers.rs | 0 .../src/mobile/vault/client_collection.rs | 0 .../src/mobile/vault/client_folders.rs | 0 .../mobile/vault/client_password_history.rs | 0 .../src/mobile/vault/client_sends.rs | 0 .../src/mobile/vault/client_totp.rs | 0 .../src/mobile/vault/client_vault.rs | 0 .../src/mobile/vault/mod.rs | 0 .../src/platform/client_platform.rs | 0 .../src/platform/domain.rs | 0 .../src/platform/fido2/authenticator.rs | 0 .../src/platform/fido2/client.rs | 0 .../src/platform/fido2/mod.rs | 0 .../src/platform/fido2/traits.rs | 0 .../src/platform/generate_fingerprint.rs | 0 .../src/platform/get_user_api_key.rs | 0 .../src/platform/mod.rs | 0 .../platform/secret_verification_request.rs | 0 .../src/platform/sync.rs | 0 .../src/secrets_manager/client_projects.rs | 0 .../src/secrets_manager/client_secrets.rs | 0 .../src/secrets_manager/mod.rs | 0 .../src/secrets_manager/projects/create.rs | 0 .../src/secrets_manager/projects/delete.rs | 0 .../src/secrets_manager/projects/get.rs | 0 .../src/secrets_manager/projects/list.rs | 0 .../src/secrets_manager/projects/mod.rs | 0 .../projects/project_response.rs | 0 .../src/secrets_manager/projects/update.rs | 0 .../src/secrets_manager/secrets/create.rs | 0 .../src/secrets_manager/secrets/delete.rs | 0 .../src/secrets_manager/secrets/get.rs | 0 .../src/secrets_manager/secrets/get_by_ids.rs | 0 .../src/secrets_manager/secrets/list.rs | 0 .../src/secrets_manager/secrets/mod.rs | 0 .../secrets/secret_response.rs | 0 .../src/secrets_manager/secrets/sync.rs | 0 .../src/secrets_manager/secrets/update.rs | 0 .../src/secrets_manager/state.rs | 0 .../src/tool/client_generator.rs | 0 .../src/tool/exporters/client_exporter.rs | 0 .../src/tool/exporters/mod.rs | 0 .../src/tool/mod.rs | 0 .../src/uniffi_support.rs | 0 .../{bitwarden => bitwarden-core}/src/util.rs | 0 .../src/vault/cipher/attachment.rs | 0 .../src/vault/cipher/card.rs | 0 .../src/vault/cipher/cipher.rs | 0 .../src/vault/cipher/field.rs | 0 .../src/vault/cipher/identity.rs | 0 .../src/vault/cipher/linked_id.rs | 0 .../src/vault/cipher/local_data.rs | 0 .../src/vault/cipher/login.rs | 0 .../src/vault/cipher/mod.rs | 0 .../src/vault/cipher/secure_note.rs | 0 .../src/vault/collection.rs | 0 .../src/vault/folder.rs | 0 .../src/vault/mod.rs | 0 .../src/vault/password_history.rs | 0 .../src/vault/send.rs | 0 .../src/vault/totp.rs | 0 .../tests/register.rs | 0 .../{bitwarden => bitwarden-core}/uniffi.toml | 0 136 files changed, 39 insertions(+), 27 deletions(-) rename crates/{bitwarden => bitwarden-core}/CHANGELOG.md (100%) rename crates/{bitwarden => bitwarden-core}/Cargo.toml (99%) rename crates/{bitwarden => bitwarden-core}/README.md (100%) rename crates/{bitwarden => bitwarden-core}/src/.gitignore (100%) rename crates/{bitwarden => bitwarden-core}/src/admin_console/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/admin_console/policy.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/access_token.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/access_token_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/api_token_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/auth_request_token_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/password_token_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/renew_token_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_captcha_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_payload_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_refresh_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_success_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_token_fail_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_token_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/identity_two_factor_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/authenticator.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/duo.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/email.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/organization_duo.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/remember.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/web_authn.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_provider_data/yubi_key.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/response/two_factor_providers.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/auth_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/client_auth.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/jwt_token.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/access_token.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/api_key.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/auth_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/password.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/captcha_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/authenticator.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/duo.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/email.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/remember.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/two_factor_providers.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/web_authn.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/response/two_factor/yubi_key.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/two_factor.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/password/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/password/policy.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/password/strength.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/password/validate.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/register.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/renew.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/tde.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/client/client.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/client/client_settings.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/client/encryption_settings.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/client/flags.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/client/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/error.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/lib.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/client_crypto.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/client_kdf.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/crypto.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/kdf.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_attachments.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_ciphers.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_collection.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_folders.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_password_history.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_sends.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_totp.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/client_vault.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/vault/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/client_platform.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/domain.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/fido2/authenticator.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/fido2/client.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/fido2/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/fido2/traits.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/generate_fingerprint.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/get_user_api_key.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/secret_verification_request.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/platform/sync.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/client_projects.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/client_secrets.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/create.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/delete.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/get.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/list.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/project_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/projects/update.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/create.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/delete.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/get.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/get_by_ids.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/list.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/secret_response.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/sync.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/secrets/update.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/state.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/tool/client_generator.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/tool/exporters/client_exporter.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/tool/exporters/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/tool/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/uniffi_support.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/util.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/attachment.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/card.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/cipher.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/field.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/identity.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/linked_id.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/local_data.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/login.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/cipher/secure_note.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/collection.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/folder.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/mod.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/password_history.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/send.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/vault/totp.rs (100%) rename crates/{bitwarden => bitwarden-core}/tests/register.rs (100%) rename crates/{bitwarden => bitwarden-core}/uniffi.toml (100%) diff --git a/Cargo.lock b/Cargo.lock index 64d6d8af4..0e75b7b6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,36 +368,12 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" name = "bitwarden" version = "0.5.0" dependencies = [ - "async-trait", - "base64 0.22.1", "bitwarden-api-api", "bitwarden-api-identity", + "bitwarden-core", "bitwarden-crypto", "bitwarden-exporters", "bitwarden-generators", - "chrono", - "getrandom", - "hmac", - "log", - "passkey", - "rand", - "rand_chacha", - "reqwest", - "rustls-platform-verifier", - "schemars", - "serde", - "serde_json", - "serde_qs", - "serde_repr", - "sha1", - "sha2", - "thiserror", - "tokio", - "uniffi", - "uuid", - "wiremock", - "zeroize", - "zxcvbn", ] [[package]] @@ -445,6 +421,42 @@ dependencies = [ "supports-color", ] +[[package]] +name = "bitwarden-core" +version = "0.5.0" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bitwarden-api-api", + "bitwarden-api-identity", + "bitwarden-crypto", + "bitwarden-exporters", + "bitwarden-generators", + "chrono", + "getrandom", + "hmac", + "log", + "passkey", + "rand", + "rand_chacha", + "reqwest", + "rustls-platform-verifier", + "schemars", + "serde", + "serde_json", + "serde_qs", + "serde_repr", + "sha1", + "sha2", + "thiserror", + "tokio", + "uniffi", + "uuid", + "wiremock", + "zeroize", + "zxcvbn", +] + [[package]] name = "bitwarden-crypto" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 1f32654dc..d3f2a10ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,10 +17,10 @@ keywords = ["bitwarden"] # Define dependencies that are expected to be consistent across all crates [workspace.dependencies] -bitwarden = { path = "crates/bitwarden", version = "=0.5.0" } bitwarden-api-api = { path = "crates/bitwarden-api-api", version = "=0.5.0" } bitwarden-api-identity = { path = "crates/bitwarden-api-identity", version = "=0.5.0" } bitwarden-cli = { path = "crates/bitwarden-cli", version = "=0.5.0" } +bitwarden-core = { path = "crates/bitwarden-core", version = "=0.5.0" } bitwarden-crypto = { path = "crates/bitwarden-crypto", version = "=0.5.0" } bitwarden-exporters = { path = "crates/bitwarden-exporters", version = "=0.5.0" } bitwarden-generators = { path = "crates/bitwarden-generators", version = "=0.5.0" } diff --git a/crates/bitwarden/CHANGELOG.md b/crates/bitwarden-core/CHANGELOG.md similarity index 100% rename from crates/bitwarden/CHANGELOG.md rename to crates/bitwarden-core/CHANGELOG.md diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden-core/Cargo.toml similarity index 99% rename from crates/bitwarden/Cargo.toml rename to crates/bitwarden-core/Cargo.toml index dc6014567..35dbe3952 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bitwarden" +name = "bitwarden-core" description = """ Bitwarden Secrets Manager SDK """ diff --git a/crates/bitwarden/README.md b/crates/bitwarden-core/README.md similarity index 100% rename from crates/bitwarden/README.md rename to crates/bitwarden-core/README.md diff --git a/crates/bitwarden/src/.gitignore b/crates/bitwarden-core/src/.gitignore similarity index 100% rename from crates/bitwarden/src/.gitignore rename to crates/bitwarden-core/src/.gitignore diff --git a/crates/bitwarden/src/admin_console/mod.rs b/crates/bitwarden-core/src/admin_console/mod.rs similarity index 100% rename from crates/bitwarden/src/admin_console/mod.rs rename to crates/bitwarden-core/src/admin_console/mod.rs diff --git a/crates/bitwarden/src/admin_console/policy.rs b/crates/bitwarden-core/src/admin_console/policy.rs similarity index 100% rename from crates/bitwarden/src/admin_console/policy.rs rename to crates/bitwarden-core/src/admin_console/policy.rs diff --git a/crates/bitwarden/src/auth/access_token.rs b/crates/bitwarden-core/src/auth/access_token.rs similarity index 100% rename from crates/bitwarden/src/auth/access_token.rs rename to crates/bitwarden-core/src/auth/access_token.rs diff --git a/crates/bitwarden/src/auth/api/mod.rs b/crates/bitwarden-core/src/auth/api/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/api/mod.rs rename to crates/bitwarden-core/src/auth/api/mod.rs diff --git a/crates/bitwarden/src/auth/api/request/access_token_request.rs b/crates/bitwarden-core/src/auth/api/request/access_token_request.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/access_token_request.rs rename to crates/bitwarden-core/src/auth/api/request/access_token_request.rs diff --git a/crates/bitwarden/src/auth/api/request/api_token_request.rs b/crates/bitwarden-core/src/auth/api/request/api_token_request.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/api_token_request.rs rename to crates/bitwarden-core/src/auth/api/request/api_token_request.rs diff --git a/crates/bitwarden/src/auth/api/request/auth_request_token_request.rs b/crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/auth_request_token_request.rs rename to crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs diff --git a/crates/bitwarden/src/auth/api/request/mod.rs b/crates/bitwarden-core/src/auth/api/request/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/mod.rs rename to crates/bitwarden-core/src/auth/api/request/mod.rs diff --git a/crates/bitwarden/src/auth/api/request/password_token_request.rs b/crates/bitwarden-core/src/auth/api/request/password_token_request.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/password_token_request.rs rename to crates/bitwarden-core/src/auth/api/request/password_token_request.rs diff --git a/crates/bitwarden/src/auth/api/request/renew_token_request.rs b/crates/bitwarden-core/src/auth/api/request/renew_token_request.rs similarity index 100% rename from crates/bitwarden/src/auth/api/request/renew_token_request.rs rename to crates/bitwarden-core/src/auth/api/request/renew_token_request.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_captcha_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_captcha_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_captcha_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_captcha_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_payload_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_payload_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_payload_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_payload_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_refresh_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_refresh_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_refresh_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_refresh_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_success_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_success_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_success_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_success_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_token_fail_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_token_fail_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_token_fail_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_token_fail_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_token_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_token_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_token_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_token_response.rs diff --git a/crates/bitwarden/src/auth/api/response/identity_two_factor_response.rs b/crates/bitwarden-core/src/auth/api/response/identity_two_factor_response.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/identity_two_factor_response.rs rename to crates/bitwarden-core/src/auth/api/response/identity_two_factor_response.rs diff --git a/crates/bitwarden/src/auth/api/response/mod.rs b/crates/bitwarden-core/src/auth/api/response/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/mod.rs rename to crates/bitwarden-core/src/auth/api/response/mod.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/authenticator.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/authenticator.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/authenticator.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/authenticator.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/duo.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/duo.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/duo.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/duo.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/email.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/email.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/email.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/email.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/mod.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/mod.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/mod.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/organization_duo.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/organization_duo.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/organization_duo.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/organization_duo.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/remember.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/remember.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/remember.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/remember.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/web_authn.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/web_authn.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/web_authn.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/web_authn.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_provider_data/yubi_key.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/yubi_key.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_provider_data/yubi_key.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_provider_data/yubi_key.rs diff --git a/crates/bitwarden/src/auth/api/response/two_factor_providers.rs b/crates/bitwarden-core/src/auth/api/response/two_factor_providers.rs similarity index 100% rename from crates/bitwarden/src/auth/api/response/two_factor_providers.rs rename to crates/bitwarden-core/src/auth/api/response/two_factor_providers.rs diff --git a/crates/bitwarden/src/auth/auth_request.rs b/crates/bitwarden-core/src/auth/auth_request.rs similarity index 100% rename from crates/bitwarden/src/auth/auth_request.rs rename to crates/bitwarden-core/src/auth/auth_request.rs diff --git a/crates/bitwarden/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs similarity index 100% rename from crates/bitwarden/src/auth/client_auth.rs rename to crates/bitwarden-core/src/auth/client_auth.rs diff --git a/crates/bitwarden/src/auth/jwt_token.rs b/crates/bitwarden-core/src/auth/jwt_token.rs similarity index 100% rename from crates/bitwarden/src/auth/jwt_token.rs rename to crates/bitwarden-core/src/auth/jwt_token.rs diff --git a/crates/bitwarden/src/auth/login/access_token.rs b/crates/bitwarden-core/src/auth/login/access_token.rs similarity index 100% rename from crates/bitwarden/src/auth/login/access_token.rs rename to crates/bitwarden-core/src/auth/login/access_token.rs diff --git a/crates/bitwarden/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs similarity index 100% rename from crates/bitwarden/src/auth/login/api_key.rs rename to crates/bitwarden-core/src/auth/login/api_key.rs diff --git a/crates/bitwarden/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs similarity index 100% rename from crates/bitwarden/src/auth/login/auth_request.rs rename to crates/bitwarden-core/src/auth/login/auth_request.rs diff --git a/crates/bitwarden/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/login/mod.rs rename to crates/bitwarden-core/src/auth/login/mod.rs diff --git a/crates/bitwarden/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs similarity index 100% rename from crates/bitwarden/src/auth/login/password.rs rename to crates/bitwarden-core/src/auth/login/password.rs diff --git a/crates/bitwarden/src/auth/login/response/captcha_response.rs b/crates/bitwarden-core/src/auth/login/response/captcha_response.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/captcha_response.rs rename to crates/bitwarden-core/src/auth/login/response/captcha_response.rs diff --git a/crates/bitwarden/src/auth/login/response/mod.rs b/crates/bitwarden-core/src/auth/login/response/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/mod.rs rename to crates/bitwarden-core/src/auth/login/response/mod.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/authenticator.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/authenticator.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/authenticator.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/authenticator.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/duo.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/duo.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/duo.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/duo.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/email.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/email.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/email.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/email.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/mod.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/mod.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/mod.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/remember.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/remember.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/remember.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/remember.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/two_factor_providers.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/two_factor_providers.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/two_factor_providers.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/two_factor_providers.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/web_authn.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/web_authn.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/web_authn.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/web_authn.rs diff --git a/crates/bitwarden/src/auth/login/response/two_factor/yubi_key.rs b/crates/bitwarden-core/src/auth/login/response/two_factor/yubi_key.rs similarity index 100% rename from crates/bitwarden/src/auth/login/response/two_factor/yubi_key.rs rename to crates/bitwarden-core/src/auth/login/response/two_factor/yubi_key.rs diff --git a/crates/bitwarden/src/auth/login/two_factor.rs b/crates/bitwarden-core/src/auth/login/two_factor.rs similarity index 100% rename from crates/bitwarden/src/auth/login/two_factor.rs rename to crates/bitwarden-core/src/auth/login/two_factor.rs diff --git a/crates/bitwarden/src/auth/mod.rs b/crates/bitwarden-core/src/auth/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/mod.rs rename to crates/bitwarden-core/src/auth/mod.rs diff --git a/crates/bitwarden/src/auth/password/mod.rs b/crates/bitwarden-core/src/auth/password/mod.rs similarity index 100% rename from crates/bitwarden/src/auth/password/mod.rs rename to crates/bitwarden-core/src/auth/password/mod.rs diff --git a/crates/bitwarden/src/auth/password/policy.rs b/crates/bitwarden-core/src/auth/password/policy.rs similarity index 100% rename from crates/bitwarden/src/auth/password/policy.rs rename to crates/bitwarden-core/src/auth/password/policy.rs diff --git a/crates/bitwarden/src/auth/password/strength.rs b/crates/bitwarden-core/src/auth/password/strength.rs similarity index 100% rename from crates/bitwarden/src/auth/password/strength.rs rename to crates/bitwarden-core/src/auth/password/strength.rs diff --git a/crates/bitwarden/src/auth/password/validate.rs b/crates/bitwarden-core/src/auth/password/validate.rs similarity index 100% rename from crates/bitwarden/src/auth/password/validate.rs rename to crates/bitwarden-core/src/auth/password/validate.rs diff --git a/crates/bitwarden/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs similarity index 100% rename from crates/bitwarden/src/auth/register.rs rename to crates/bitwarden-core/src/auth/register.rs diff --git a/crates/bitwarden/src/auth/renew.rs b/crates/bitwarden-core/src/auth/renew.rs similarity index 100% rename from crates/bitwarden/src/auth/renew.rs rename to crates/bitwarden-core/src/auth/renew.rs diff --git a/crates/bitwarden/src/auth/tde.rs b/crates/bitwarden-core/src/auth/tde.rs similarity index 100% rename from crates/bitwarden/src/auth/tde.rs rename to crates/bitwarden-core/src/auth/tde.rs diff --git a/crates/bitwarden/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs similarity index 100% rename from crates/bitwarden/src/client/client.rs rename to crates/bitwarden-core/src/client/client.rs diff --git a/crates/bitwarden/src/client/client_settings.rs b/crates/bitwarden-core/src/client/client_settings.rs similarity index 100% rename from crates/bitwarden/src/client/client_settings.rs rename to crates/bitwarden-core/src/client/client_settings.rs diff --git a/crates/bitwarden/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs similarity index 100% rename from crates/bitwarden/src/client/encryption_settings.rs rename to crates/bitwarden-core/src/client/encryption_settings.rs diff --git a/crates/bitwarden/src/client/flags.rs b/crates/bitwarden-core/src/client/flags.rs similarity index 100% rename from crates/bitwarden/src/client/flags.rs rename to crates/bitwarden-core/src/client/flags.rs diff --git a/crates/bitwarden/src/client/mod.rs b/crates/bitwarden-core/src/client/mod.rs similarity index 100% rename from crates/bitwarden/src/client/mod.rs rename to crates/bitwarden-core/src/client/mod.rs diff --git a/crates/bitwarden/src/error.rs b/crates/bitwarden-core/src/error.rs similarity index 100% rename from crates/bitwarden/src/error.rs rename to crates/bitwarden-core/src/error.rs diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden-core/src/lib.rs similarity index 100% rename from crates/bitwarden/src/lib.rs rename to crates/bitwarden-core/src/lib.rs diff --git a/crates/bitwarden/src/mobile/client_crypto.rs b/crates/bitwarden-core/src/mobile/client_crypto.rs similarity index 100% rename from crates/bitwarden/src/mobile/client_crypto.rs rename to crates/bitwarden-core/src/mobile/client_crypto.rs diff --git a/crates/bitwarden/src/mobile/client_kdf.rs b/crates/bitwarden-core/src/mobile/client_kdf.rs similarity index 100% rename from crates/bitwarden/src/mobile/client_kdf.rs rename to crates/bitwarden-core/src/mobile/client_kdf.rs diff --git a/crates/bitwarden/src/mobile/crypto.rs b/crates/bitwarden-core/src/mobile/crypto.rs similarity index 100% rename from crates/bitwarden/src/mobile/crypto.rs rename to crates/bitwarden-core/src/mobile/crypto.rs diff --git a/crates/bitwarden/src/mobile/kdf.rs b/crates/bitwarden-core/src/mobile/kdf.rs similarity index 100% rename from crates/bitwarden/src/mobile/kdf.rs rename to crates/bitwarden-core/src/mobile/kdf.rs diff --git a/crates/bitwarden/src/mobile/mod.rs b/crates/bitwarden-core/src/mobile/mod.rs similarity index 100% rename from crates/bitwarden/src/mobile/mod.rs rename to crates/bitwarden-core/src/mobile/mod.rs diff --git a/crates/bitwarden/src/mobile/vault/client_attachments.rs b/crates/bitwarden-core/src/mobile/vault/client_attachments.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_attachments.rs rename to crates/bitwarden-core/src/mobile/vault/client_attachments.rs diff --git a/crates/bitwarden/src/mobile/vault/client_ciphers.rs b/crates/bitwarden-core/src/mobile/vault/client_ciphers.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_ciphers.rs rename to crates/bitwarden-core/src/mobile/vault/client_ciphers.rs diff --git a/crates/bitwarden/src/mobile/vault/client_collection.rs b/crates/bitwarden-core/src/mobile/vault/client_collection.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_collection.rs rename to crates/bitwarden-core/src/mobile/vault/client_collection.rs diff --git a/crates/bitwarden/src/mobile/vault/client_folders.rs b/crates/bitwarden-core/src/mobile/vault/client_folders.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_folders.rs rename to crates/bitwarden-core/src/mobile/vault/client_folders.rs diff --git a/crates/bitwarden/src/mobile/vault/client_password_history.rs b/crates/bitwarden-core/src/mobile/vault/client_password_history.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_password_history.rs rename to crates/bitwarden-core/src/mobile/vault/client_password_history.rs diff --git a/crates/bitwarden/src/mobile/vault/client_sends.rs b/crates/bitwarden-core/src/mobile/vault/client_sends.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_sends.rs rename to crates/bitwarden-core/src/mobile/vault/client_sends.rs diff --git a/crates/bitwarden/src/mobile/vault/client_totp.rs b/crates/bitwarden-core/src/mobile/vault/client_totp.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_totp.rs rename to crates/bitwarden-core/src/mobile/vault/client_totp.rs diff --git a/crates/bitwarden/src/mobile/vault/client_vault.rs b/crates/bitwarden-core/src/mobile/vault/client_vault.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/client_vault.rs rename to crates/bitwarden-core/src/mobile/vault/client_vault.rs diff --git a/crates/bitwarden/src/mobile/vault/mod.rs b/crates/bitwarden-core/src/mobile/vault/mod.rs similarity index 100% rename from crates/bitwarden/src/mobile/vault/mod.rs rename to crates/bitwarden-core/src/mobile/vault/mod.rs diff --git a/crates/bitwarden/src/platform/client_platform.rs b/crates/bitwarden-core/src/platform/client_platform.rs similarity index 100% rename from crates/bitwarden/src/platform/client_platform.rs rename to crates/bitwarden-core/src/platform/client_platform.rs diff --git a/crates/bitwarden/src/platform/domain.rs b/crates/bitwarden-core/src/platform/domain.rs similarity index 100% rename from crates/bitwarden/src/platform/domain.rs rename to crates/bitwarden-core/src/platform/domain.rs diff --git a/crates/bitwarden/src/platform/fido2/authenticator.rs b/crates/bitwarden-core/src/platform/fido2/authenticator.rs similarity index 100% rename from crates/bitwarden/src/platform/fido2/authenticator.rs rename to crates/bitwarden-core/src/platform/fido2/authenticator.rs diff --git a/crates/bitwarden/src/platform/fido2/client.rs b/crates/bitwarden-core/src/platform/fido2/client.rs similarity index 100% rename from crates/bitwarden/src/platform/fido2/client.rs rename to crates/bitwarden-core/src/platform/fido2/client.rs diff --git a/crates/bitwarden/src/platform/fido2/mod.rs b/crates/bitwarden-core/src/platform/fido2/mod.rs similarity index 100% rename from crates/bitwarden/src/platform/fido2/mod.rs rename to crates/bitwarden-core/src/platform/fido2/mod.rs diff --git a/crates/bitwarden/src/platform/fido2/traits.rs b/crates/bitwarden-core/src/platform/fido2/traits.rs similarity index 100% rename from crates/bitwarden/src/platform/fido2/traits.rs rename to crates/bitwarden-core/src/platform/fido2/traits.rs diff --git a/crates/bitwarden/src/platform/generate_fingerprint.rs b/crates/bitwarden-core/src/platform/generate_fingerprint.rs similarity index 100% rename from crates/bitwarden/src/platform/generate_fingerprint.rs rename to crates/bitwarden-core/src/platform/generate_fingerprint.rs diff --git a/crates/bitwarden/src/platform/get_user_api_key.rs b/crates/bitwarden-core/src/platform/get_user_api_key.rs similarity index 100% rename from crates/bitwarden/src/platform/get_user_api_key.rs rename to crates/bitwarden-core/src/platform/get_user_api_key.rs diff --git a/crates/bitwarden/src/platform/mod.rs b/crates/bitwarden-core/src/platform/mod.rs similarity index 100% rename from crates/bitwarden/src/platform/mod.rs rename to crates/bitwarden-core/src/platform/mod.rs diff --git a/crates/bitwarden/src/platform/secret_verification_request.rs b/crates/bitwarden-core/src/platform/secret_verification_request.rs similarity index 100% rename from crates/bitwarden/src/platform/secret_verification_request.rs rename to crates/bitwarden-core/src/platform/secret_verification_request.rs diff --git a/crates/bitwarden/src/platform/sync.rs b/crates/bitwarden-core/src/platform/sync.rs similarity index 100% rename from crates/bitwarden/src/platform/sync.rs rename to crates/bitwarden-core/src/platform/sync.rs diff --git a/crates/bitwarden/src/secrets_manager/client_projects.rs b/crates/bitwarden-core/src/secrets_manager/client_projects.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/client_projects.rs rename to crates/bitwarden-core/src/secrets_manager/client_projects.rs diff --git a/crates/bitwarden/src/secrets_manager/client_secrets.rs b/crates/bitwarden-core/src/secrets_manager/client_secrets.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/client_secrets.rs rename to crates/bitwarden-core/src/secrets_manager/client_secrets.rs diff --git a/crates/bitwarden/src/secrets_manager/mod.rs b/crates/bitwarden-core/src/secrets_manager/mod.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/mod.rs rename to crates/bitwarden-core/src/secrets_manager/mod.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/create.rs b/crates/bitwarden-core/src/secrets_manager/projects/create.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/create.rs rename to crates/bitwarden-core/src/secrets_manager/projects/create.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/delete.rs b/crates/bitwarden-core/src/secrets_manager/projects/delete.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/delete.rs rename to crates/bitwarden-core/src/secrets_manager/projects/delete.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/get.rs b/crates/bitwarden-core/src/secrets_manager/projects/get.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/get.rs rename to crates/bitwarden-core/src/secrets_manager/projects/get.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/list.rs b/crates/bitwarden-core/src/secrets_manager/projects/list.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/list.rs rename to crates/bitwarden-core/src/secrets_manager/projects/list.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/mod.rs b/crates/bitwarden-core/src/secrets_manager/projects/mod.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/mod.rs rename to crates/bitwarden-core/src/secrets_manager/projects/mod.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/project_response.rs b/crates/bitwarden-core/src/secrets_manager/projects/project_response.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/project_response.rs rename to crates/bitwarden-core/src/secrets_manager/projects/project_response.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/update.rs b/crates/bitwarden-core/src/secrets_manager/projects/update.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/update.rs rename to crates/bitwarden-core/src/secrets_manager/projects/update.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/create.rs b/crates/bitwarden-core/src/secrets_manager/secrets/create.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/create.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/create.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/delete.rs b/crates/bitwarden-core/src/secrets_manager/secrets/delete.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/delete.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/delete.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/get.rs b/crates/bitwarden-core/src/secrets_manager/secrets/get.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/get.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/get.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs b/crates/bitwarden-core/src/secrets_manager/secrets/get_by_ids.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/get_by_ids.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/list.rs b/crates/bitwarden-core/src/secrets_manager/secrets/list.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/list.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/list.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/mod.rs b/crates/bitwarden-core/src/secrets_manager/secrets/mod.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/mod.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/mod.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs b/crates/bitwarden-core/src/secrets_manager/secrets/secret_response.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/secret_response.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/secret_response.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/sync.rs b/crates/bitwarden-core/src/secrets_manager/secrets/sync.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/sync.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/sync.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/update.rs b/crates/bitwarden-core/src/secrets_manager/secrets/update.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/update.rs rename to crates/bitwarden-core/src/secrets_manager/secrets/update.rs diff --git a/crates/bitwarden/src/secrets_manager/state.rs b/crates/bitwarden-core/src/secrets_manager/state.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/state.rs rename to crates/bitwarden-core/src/secrets_manager/state.rs diff --git a/crates/bitwarden/src/tool/client_generator.rs b/crates/bitwarden-core/src/tool/client_generator.rs similarity index 100% rename from crates/bitwarden/src/tool/client_generator.rs rename to crates/bitwarden-core/src/tool/client_generator.rs diff --git a/crates/bitwarden/src/tool/exporters/client_exporter.rs b/crates/bitwarden-core/src/tool/exporters/client_exporter.rs similarity index 100% rename from crates/bitwarden/src/tool/exporters/client_exporter.rs rename to crates/bitwarden-core/src/tool/exporters/client_exporter.rs diff --git a/crates/bitwarden/src/tool/exporters/mod.rs b/crates/bitwarden-core/src/tool/exporters/mod.rs similarity index 100% rename from crates/bitwarden/src/tool/exporters/mod.rs rename to crates/bitwarden-core/src/tool/exporters/mod.rs diff --git a/crates/bitwarden/src/tool/mod.rs b/crates/bitwarden-core/src/tool/mod.rs similarity index 100% rename from crates/bitwarden/src/tool/mod.rs rename to crates/bitwarden-core/src/tool/mod.rs diff --git a/crates/bitwarden/src/uniffi_support.rs b/crates/bitwarden-core/src/uniffi_support.rs similarity index 100% rename from crates/bitwarden/src/uniffi_support.rs rename to crates/bitwarden-core/src/uniffi_support.rs diff --git a/crates/bitwarden/src/util.rs b/crates/bitwarden-core/src/util.rs similarity index 100% rename from crates/bitwarden/src/util.rs rename to crates/bitwarden-core/src/util.rs diff --git a/crates/bitwarden/src/vault/cipher/attachment.rs b/crates/bitwarden-core/src/vault/cipher/attachment.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/attachment.rs rename to crates/bitwarden-core/src/vault/cipher/attachment.rs diff --git a/crates/bitwarden/src/vault/cipher/card.rs b/crates/bitwarden-core/src/vault/cipher/card.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/card.rs rename to crates/bitwarden-core/src/vault/cipher/card.rs diff --git a/crates/bitwarden/src/vault/cipher/cipher.rs b/crates/bitwarden-core/src/vault/cipher/cipher.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/cipher.rs rename to crates/bitwarden-core/src/vault/cipher/cipher.rs diff --git a/crates/bitwarden/src/vault/cipher/field.rs b/crates/bitwarden-core/src/vault/cipher/field.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/field.rs rename to crates/bitwarden-core/src/vault/cipher/field.rs diff --git a/crates/bitwarden/src/vault/cipher/identity.rs b/crates/bitwarden-core/src/vault/cipher/identity.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/identity.rs rename to crates/bitwarden-core/src/vault/cipher/identity.rs diff --git a/crates/bitwarden/src/vault/cipher/linked_id.rs b/crates/bitwarden-core/src/vault/cipher/linked_id.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/linked_id.rs rename to crates/bitwarden-core/src/vault/cipher/linked_id.rs diff --git a/crates/bitwarden/src/vault/cipher/local_data.rs b/crates/bitwarden-core/src/vault/cipher/local_data.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/local_data.rs rename to crates/bitwarden-core/src/vault/cipher/local_data.rs diff --git a/crates/bitwarden/src/vault/cipher/login.rs b/crates/bitwarden-core/src/vault/cipher/login.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/login.rs rename to crates/bitwarden-core/src/vault/cipher/login.rs diff --git a/crates/bitwarden/src/vault/cipher/mod.rs b/crates/bitwarden-core/src/vault/cipher/mod.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/mod.rs rename to crates/bitwarden-core/src/vault/cipher/mod.rs diff --git a/crates/bitwarden/src/vault/cipher/secure_note.rs b/crates/bitwarden-core/src/vault/cipher/secure_note.rs similarity index 100% rename from crates/bitwarden/src/vault/cipher/secure_note.rs rename to crates/bitwarden-core/src/vault/cipher/secure_note.rs diff --git a/crates/bitwarden/src/vault/collection.rs b/crates/bitwarden-core/src/vault/collection.rs similarity index 100% rename from crates/bitwarden/src/vault/collection.rs rename to crates/bitwarden-core/src/vault/collection.rs diff --git a/crates/bitwarden/src/vault/folder.rs b/crates/bitwarden-core/src/vault/folder.rs similarity index 100% rename from crates/bitwarden/src/vault/folder.rs rename to crates/bitwarden-core/src/vault/folder.rs diff --git a/crates/bitwarden/src/vault/mod.rs b/crates/bitwarden-core/src/vault/mod.rs similarity index 100% rename from crates/bitwarden/src/vault/mod.rs rename to crates/bitwarden-core/src/vault/mod.rs diff --git a/crates/bitwarden/src/vault/password_history.rs b/crates/bitwarden-core/src/vault/password_history.rs similarity index 100% rename from crates/bitwarden/src/vault/password_history.rs rename to crates/bitwarden-core/src/vault/password_history.rs diff --git a/crates/bitwarden/src/vault/send.rs b/crates/bitwarden-core/src/vault/send.rs similarity index 100% rename from crates/bitwarden/src/vault/send.rs rename to crates/bitwarden-core/src/vault/send.rs diff --git a/crates/bitwarden/src/vault/totp.rs b/crates/bitwarden-core/src/vault/totp.rs similarity index 100% rename from crates/bitwarden/src/vault/totp.rs rename to crates/bitwarden-core/src/vault/totp.rs diff --git a/crates/bitwarden/tests/register.rs b/crates/bitwarden-core/tests/register.rs similarity index 100% rename from crates/bitwarden/tests/register.rs rename to crates/bitwarden-core/tests/register.rs diff --git a/crates/bitwarden/uniffi.toml b/crates/bitwarden-core/uniffi.toml similarity index 100% rename from crates/bitwarden/uniffi.toml rename to crates/bitwarden-core/uniffi.toml From 677ba47981608e14a9f8dd8c9b383162ce147528 Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 24 May 2024 13:06:40 +0200 Subject: [PATCH 02/28] Expose new Bitwarden crate with wrappers --- Cargo.lock | 4 +- Cargo.toml | 1 + crates/bitwarden-core/Cargo.toml | 9 +--- .../bitwarden-core/src/auth/auth_request.rs | 10 +---- crates/bitwarden-core/src/client/client.rs | 2 +- crates/bitwarden-core/src/error.rs | 13 ------ crates/bitwarden-core/src/lib.rs | 7 --- crates/bitwarden-core/src/tool/mod.rs | 2 - crates/bitwarden-crypto/Cargo.toml | 2 +- crates/bitwarden-exporters/Cargo.toml | 2 +- crates/bitwarden-generators/Cargo.toml | 1 + .../src}/client_generator.rs | 38 ++++++++++------ crates/bitwarden-generators/src/lib.rs | 2 + crates/bitwarden-uniffi/src/tool/mod.rs | 11 +++-- crates/bitwarden/Cargo.toml | 44 +++++++++++++++++++ crates/bitwarden/src/lib.rs | 9 ++++ crates/bw/src/main.rs | 1 + 17 files changed, 98 insertions(+), 60 deletions(-) rename crates/{bitwarden-core/src/tool => bitwarden-generators/src}/client_generator.rs (75%) create mode 100644 crates/bitwarden/Cargo.toml create mode 100644 crates/bitwarden/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0e75b7b6f..d44c3bd48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,12 +426,11 @@ name = "bitwarden-core" version = "0.5.0" dependencies = [ "async-trait", - "base64 0.21.7", + "base64 0.22.1", "bitwarden-api-api", "bitwarden-api-identity", "bitwarden-crypto", "bitwarden-exporters", - "bitwarden-generators", "chrono", "getrandom", "hmac", @@ -507,6 +506,7 @@ dependencies = [ name = "bitwarden-generators" version = "0.5.0" dependencies = [ + "bitwarden-core", "bitwarden-crypto", "rand", "rand_chacha", diff --git a/Cargo.toml b/Cargo.toml index d3f2a10ca..2da09446c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ keywords = ["bitwarden"] # Define dependencies that are expected to be consistent across all crates [workspace.dependencies] +bitwarden = { path = "crates/bitwarden", version = "=0.5.0" } bitwarden-api-api = { path = "crates/bitwarden-api-api", version = "=0.5.0" } bitwarden-api-identity = { path = "crates/bitwarden-api-identity", version = "=0.5.0" } bitwarden-cli = { path = "crates/bitwarden-cli", version = "=0.5.0" } diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index 35dbe3952..2fe4679b2 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -16,10 +16,7 @@ license-file.workspace = true [features] default = ["secrets"] -internal = [ - "dep:bitwarden-exporters", - "dep:bitwarden-generators", -] # Internal testing methods +internal = ["dep:bitwarden-exporters"] # Internal testing methods no-memory-hardening = [ "bitwarden-crypto/no-memory-hardening", ] # Disable memory hardening features @@ -27,19 +24,17 @@ mobile = [ "internal", "dep:uniffi", "bitwarden-crypto/mobile", - "bitwarden-generators/mobile", ] # Mobile-specific features secrets = [] # Secrets manager API wasm-bindgen = ["chrono/wasmbind"] [dependencies] async-trait = ">=0.1.80, <0.2" -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-api-api = { workspace = true } bitwarden-api-identity = { workspace = true } bitwarden-crypto = { workspace = true } bitwarden-exporters = { workspace = true, optional = true } -bitwarden-generators = { workspace = true, optional = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", "serde", diff --git a/crates/bitwarden-core/src/auth/auth_request.rs b/crates/bitwarden-core/src/auth/auth_request.rs index ca47ad579..1bd0af2c0 100644 --- a/crates/bitwarden-core/src/auth/auth_request.rs +++ b/crates/bitwarden-core/src/auth/auth_request.rs @@ -5,7 +5,6 @@ use bitwarden_crypto::{ }; #[cfg(feature = "mobile")] use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; -use bitwarden_generators::{password, PasswordGeneratorRequest}; use crate::{error::Error, Client}; @@ -41,14 +40,7 @@ pub(crate) fn new_auth_request(email: &str) -> Result &reqwest::Client { + pub fn get_http_client(&self) -> &reqwest::Client { &self.__api_configurations.external_client } diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index fdae93fac..186f3518d 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -6,8 +6,6 @@ use bitwarden_api_api::apis::Error as ApiError; use bitwarden_api_identity::apis::Error as IdentityError; #[cfg(feature = "internal")] use bitwarden_exporters::ExportError; -#[cfg(feature = "internal")] -use bitwarden_generators::{PassphraseError, PasswordError, UsernameError}; use passkey::client::WebauthnError; use reqwest::StatusCode; use thiserror::Error; @@ -54,17 +52,6 @@ pub enum Error { #[error("The state file could not be read")] InvalidStateFile, - // Generators - #[cfg(feature = "internal")] - #[error(transparent)] - UsernameError(#[from] UsernameError), - #[cfg(feature = "internal")] - #[error(transparent)] - PassphraseError(#[from] PassphraseError), - #[cfg(feature = "internal")] - #[error(transparent)] - PasswordError(#[from] PasswordError), - #[cfg(feature = "internal")] #[error(transparent)] ExportError(#[from] ExportError), diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index b1f3d09bd..6614b6b07 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -75,11 +75,4 @@ pub use client::Client; #[doc = include_str!("../README.md")] mod readme {} -#[cfg(feature = "internal")] -pub mod generators { - pub use bitwarden_generators::{ - PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, - }; -} - pub use bitwarden_crypto::ZeroizingAllocator; diff --git a/crates/bitwarden-core/src/tool/mod.rs b/crates/bitwarden-core/src/tool/mod.rs index a94528163..8034151d7 100644 --- a/crates/bitwarden-core/src/tool/mod.rs +++ b/crates/bitwarden-core/src/tool/mod.rs @@ -1,4 +1,2 @@ mod exporters; pub use exporters::{ClientExporters, ExportFormat}; -mod client_generator; -pub use client_generator::ClientGenerator; diff --git a/crates/bitwarden-crypto/Cargo.toml b/crates/bitwarden-crypto/Cargo.toml index b6b2e4e26..2744b932f 100644 --- a/crates/bitwarden-crypto/Cargo.toml +++ b/crates/bitwarden-crypto/Cargo.toml @@ -26,7 +26,7 @@ argon2 = { version = ">=0.5.0, <0.6", features = [ "std", "zeroize", ], default-features = false } -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] } generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] } hkdf = ">=0.12.3, <0.13" diff --git a/crates/bitwarden-exporters/Cargo.toml b/crates/bitwarden-exporters/Cargo.toml index 9ed860af6..09c8132d5 100644 --- a/crates/bitwarden-exporters/Cargo.toml +++ b/crates/bitwarden-exporters/Cargo.toml @@ -15,7 +15,7 @@ license-file.workspace = true keywords.workspace = true [dependencies] -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-crypto = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", diff --git a/crates/bitwarden-generators/Cargo.toml b/crates/bitwarden-generators/Cargo.toml index 2fbcc7b02..9695b6687 100644 --- a/crates/bitwarden-generators/Cargo.toml +++ b/crates/bitwarden-generators/Cargo.toml @@ -17,6 +17,7 @@ keywords.workspace = true mobile = ["dep:uniffi"] # Mobile-specific features [dependencies] +bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } rand = ">=0.8.5, <0.9" reqwest = { version = ">=0.12, <0.13", features = [ diff --git a/crates/bitwarden-core/src/tool/client_generator.rs b/crates/bitwarden-generators/src/client_generator.rs similarity index 75% rename from crates/bitwarden-core/src/tool/client_generator.rs rename to crates/bitwarden-generators/src/client_generator.rs index 16c786f9b..0cf4e4296 100644 --- a/crates/bitwarden-core/src/tool/client_generator.rs +++ b/crates/bitwarden-generators/src/client_generator.rs @@ -1,16 +1,19 @@ -use bitwarden_generators::{passphrase, password, username}; +use bitwarden_core::Client; use crate::{ - error::Result, - generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest}, - Client, + passphrase, password, username, PassphraseError, PassphraseGeneratorRequest, PasswordError, + PasswordGeneratorRequest, UsernameError, UsernameGeneratorRequest, }; pub struct ClientGenerator<'a> { - pub(crate) client: &'a crate::Client, + client: &'a Client, } impl<'a> ClientGenerator<'a> { + fn new(client: &'a Client) -> Self { + Self { client } + } + /// Generates a random password. /// /// The character sets and password length can be customized using the `input` parameter. @@ -32,8 +35,8 @@ impl<'a> ClientGenerator<'a> { /// Ok(()) /// } /// ``` - pub async fn password(&self, input: PasswordGeneratorRequest) -> Result { - Ok(password(input)?) + pub async fn password(&self, input: PasswordGeneratorRequest) -> Result { + password(input) } /// Generates a random passphrase. @@ -57,8 +60,11 @@ impl<'a> ClientGenerator<'a> { /// Ok(()) /// } /// ``` - pub async fn passphrase(&self, input: PassphraseGeneratorRequest) -> Result { - Ok(passphrase(input)?) + pub async fn passphrase( + &self, + input: PassphraseGeneratorRequest, + ) -> Result { + passphrase(input) } /// Generates a random username. @@ -80,13 +86,17 @@ impl<'a> ClientGenerator<'a> { /// Ok(()) /// } /// ``` - pub async fn username(&self, input: UsernameGeneratorRequest) -> Result { - Ok(username(input, self.client.get_http_client()).await?) + pub async fn username(&self, input: UsernameGeneratorRequest) -> Result { + username(input, self.client.get_http_client()).await } } -impl<'a> Client { - pub fn generator(&'a self) -> ClientGenerator<'a> { - ClientGenerator { client: self } +pub trait ClientGeneratorExt<'a> { + fn generator(&'a self) -> ClientGenerator<'a>; +} + +impl<'a> ClientGeneratorExt<'a> for Client { + fn generator(&'a self) -> ClientGenerator<'a> { + ClientGenerator::new(self) } } diff --git a/crates/bitwarden-generators/src/lib.rs b/crates/bitwarden-generators/src/lib.rs index 335ec92b9..4b7a08038 100644 --- a/crates/bitwarden-generators/src/lib.rs +++ b/crates/bitwarden-generators/src/lib.rs @@ -5,6 +5,8 @@ mod util; pub use password::{password, PasswordError, PasswordGeneratorRequest}; mod username; pub use username::{username, ForwarderServiceType, UsernameError, UsernameGeneratorRequest}; +mod client_generator; +pub use client_generator::{ClientGenerator, ClientGeneratorExt}; mod username_forwarders; #[cfg(feature = "mobile")] diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index 4a4ea2401..8043cf58f 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -1,9 +1,11 @@ use std::sync::Arc; use bitwarden::{ + error::Error, generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest}, tool::ExportFormat, vault::{Cipher, Collection, Folder}, + ClientGeneratorExt, }; use crate::{error::Result, Client}; @@ -22,7 +24,8 @@ impl ClientGenerators { .await .generator() .password(settings) - .await?) + .await + .map_err(|_| Error::VaultLocked)?) } /// **API Draft:** Generate Passphrase @@ -34,7 +37,8 @@ impl ClientGenerators { .await .generator() .passphrase(settings) - .await?) + .await + .map_err(|_| Error::VaultLocked)?) } /// **API Draft:** Generate Username @@ -46,7 +50,8 @@ impl ClientGenerators { .await .generator() .username(settings) - .await?) + .await + .map_err(|_| Error::VaultLocked)?) } } diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml new file mode 100644 index 000000000..7aa65c6f3 --- /dev/null +++ b/crates/bitwarden/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "bitwarden" +description = """ +Bitwarden Secrets Manager SDK +""" +keywords = ["bitwarden", "secrets-manager"] + +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +homepage.workspace = true +repository.workspace = true +license-file.workspace = true + +[features] +default = ["secrets"] + +internal = [ + "dep:bitwarden-exporters", + "dep:bitwarden-generators", + "bitwarden-core/internal", +] # Internal testing methods +no-memory-hardening = [ + "bitwarden-core/no-memory-hardening", +] # Disable memory hardening features +mobile = [ + "internal", + "bitwarden-core/mobile", + "bitwarden-crypto/mobile", + "bitwarden-generators/mobile", +] # Mobile-specific features +secrets = ["bitwarden-core/internal"] # Secrets manager API + +[dependencies] +bitwarden-api-api = { workspace = true } +bitwarden-api-identity = { workspace = true } +bitwarden-core = { workspace = true } +bitwarden-crypto = { workspace = true } +bitwarden-exporters = { workspace = true, optional = true } +bitwarden-generators = { workspace = true, optional = true } + +[lints] +workspace = true diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs new file mode 100644 index 000000000..c91bd1104 --- /dev/null +++ b/crates/bitwarden/src/lib.rs @@ -0,0 +1,9 @@ +pub use bitwarden_core::*; +#[cfg(feature = "internal")] +pub use bitwarden_generators::ClientGeneratorExt; +#[cfg(feature = "internal")] +pub mod generators { + pub use bitwarden_generators::{ + PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, + }; +} diff --git a/crates/bw/src/main.rs b/crates/bw/src/main.rs index d973c4074..90998655b 100644 --- a/crates/bw/src/main.rs +++ b/crates/bw/src/main.rs @@ -2,6 +2,7 @@ use bitwarden::{ auth::RegisterRequest, client::client_settings::ClientSettings, generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, + ClientGeneratorExt, }; use bitwarden_cli::{install_color_eyre, text_prompt_when_none, Color}; use bitwarden_crypto::SensitiveString; From 83818b9fb1b2a9d7cd5a88c201b4b1f706d9f0db Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 27 May 2024 11:00:51 +0200 Subject: [PATCH 03/28] Move secrets manager to separate crate --- Cargo.lock | 22 ++++++ Cargo.toml | 1 + crates/bitwarden-core/Cargo.toml | 2 +- crates/bitwarden-core/src/client/client.rs | 6 +- .../src/client/encryption_settings.rs | 2 +- crates/bitwarden-core/src/client/mod.rs | 2 +- .../src/secrets_manager/client_projects.rs | 41 ----------- .../src/secrets_manager/client_secrets.rs | 62 ---------------- .../bitwarden-core/src/secrets_manager/mod.rs | 8 --- crates/bitwarden-json/src/client.rs | 4 ++ crates/bitwarden-sm/Cargo.toml | 43 ++++++++++++ crates/bitwarden-sm/src/client_projects.rs | 50 +++++++++++++ crates/bitwarden-sm/src/client_secrets.rs | 70 +++++++++++++++++++ crates/bitwarden-sm/src/lib.rs | 21 ++++++ .../src}/projects/create.rs | 7 +- .../src}/projects/delete.rs | 7 +- .../src}/projects/get.rs | 2 +- .../src}/projects/list.rs | 2 +- .../src}/projects/mod.rs | 0 .../src}/projects/project_response.rs | 7 +- .../src}/projects/update.rs | 2 +- .../src}/secrets/create.rs | 2 +- .../src}/secrets/delete.rs | 7 +- .../src}/secrets/get.rs | 2 +- .../src}/secrets/get_by_ids.rs | 2 +- .../src}/secrets/list.rs | 6 +- .../src}/secrets/mod.rs | 0 .../src}/secrets/secret_response.rs | 7 +- .../src}/secrets/sync.rs | 8 +-- .../src}/secrets/update.rs | 2 +- crates/bitwarden/Cargo.toml | 3 +- crates/bitwarden/src/lib.rs | 15 ++++ crates/bws/src/main.rs | 1 + 33 files changed, 263 insertions(+), 153 deletions(-) delete mode 100644 crates/bitwarden-core/src/secrets_manager/client_projects.rs delete mode 100644 crates/bitwarden-core/src/secrets_manager/client_secrets.rs create mode 100644 crates/bitwarden-sm/Cargo.toml create mode 100644 crates/bitwarden-sm/src/client_projects.rs create mode 100644 crates/bitwarden-sm/src/client_secrets.rs create mode 100644 crates/bitwarden-sm/src/lib.rs rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/create.rs (92%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/delete.rs (96%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/get.rs (92%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/list.rs (98%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/mod.rs (100%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/project_response.rs (92%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/projects/update.rs (98%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/create.rs (98%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/delete.rs (96%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/get.rs (93%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/get_by_ids.rs (94%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/list.rs (98%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/mod.rs (100%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/secret_response.rs (96%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/sync.rs (94%) rename crates/{bitwarden-core/src/secrets_manager => bitwarden-sm/src}/secrets/update.rs (98%) diff --git a/Cargo.lock b/Cargo.lock index d44c3bd48..75e0d58b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -374,6 +374,7 @@ dependencies = [ "bitwarden-crypto", "bitwarden-exporters", "bitwarden-generators", + "bitwarden-sm", ] [[package]] @@ -556,6 +557,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "bitwarden-sm" +version = "0.5.0" +dependencies = [ + "bitwarden-api-api", + "bitwarden-core", + "bitwarden-crypto", + "chrono", + "rand", + "rand_chacha", + "reqwest", + "schemars", + "serde", + "serde_json", + "thiserror", + "tokio", + "uniffi", + "uuid", + "wiremock", +] + [[package]] name = "bitwarden-uniffi" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 2da09446c..be359da0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ bitwarden-core = { path = "crates/bitwarden-core", version = "=0.5.0" } bitwarden-crypto = { path = "crates/bitwarden-crypto", version = "=0.5.0" } bitwarden-exporters = { path = "crates/bitwarden-exporters", version = "=0.5.0" } bitwarden-generators = { path = "crates/bitwarden-generators", version = "=0.5.0" } +bitwarden-sm = { path = "crates/bitwarden-sm", version = "=0.5.0" } [workspace.lints.clippy] unwrap_used = "deny" diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index 2fe4679b2..3d5527714 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bitwarden-core" description = """ -Bitwarden Secrets Manager SDK +Internal crate for the bitwarden crate. Do not use. """ keywords = ["bitwarden", "secrets-manager"] diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index 35111a8bc..898003ed8 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -29,7 +29,7 @@ use crate::{ }; #[derive(Debug)] -pub(crate) struct ApiConfigurations { +pub 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. @@ -168,7 +168,7 @@ impl Client { &self.flags } - pub(crate) async fn get_api_configurations(&mut self) -> &ApiConfigurations { + pub async fn get_api_configurations(&mut self) -> &ApiConfigurations { // 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(); @@ -217,7 +217,7 @@ impl Client { } } - pub(crate) fn get_encryption_settings(&self) -> Result<&EncryptionSettings> { + pub fn get_encryption_settings(&self) -> Result<&EncryptionSettings> { self.encryption_settings.as_ref().ok_or(Error::VaultLocked) } diff --git a/crates/bitwarden-core/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs index 463c67815..eb868e56d 100644 --- a/crates/bitwarden-core/src/client/encryption_settings.rs +++ b/crates/bitwarden-core/src/client/encryption_settings.rs @@ -93,7 +93,7 @@ impl EncryptionSettings { Ok(self) } - pub(crate) fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey> { + pub fn get_key(&self, org_id: &Option) -> Option<&SymmetricCryptoKey> { // If we don't have a private key set (to decode multiple org keys), we just use the main // user key if self.private_key.is_none() { diff --git a/crates/bitwarden-core/src/client/mod.rs b/crates/bitwarden-core/src/client/mod.rs index 0c703570f..87b3593e3 100644 --- a/crates/bitwarden-core/src/client/mod.rs +++ b/crates/bitwarden-core/src/client/mod.rs @@ -4,7 +4,7 @@ pub(crate) use client::*; #[allow(clippy::module_inception)] mod client; pub mod client_settings; -pub(crate) mod encryption_settings; +pub mod encryption_settings; #[cfg(feature = "internal")] mod flags; diff --git a/crates/bitwarden-core/src/secrets_manager/client_projects.rs b/crates/bitwarden-core/src/secrets_manager/client_projects.rs deleted file mode 100644 index acd4adfae..000000000 --- a/crates/bitwarden-core/src/secrets_manager/client_projects.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::{ - error::Result, - secrets_manager::projects::{ - create_project, delete_projects, get_project, list_projects, update_project, - ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectResponse, - ProjectsDeleteRequest, ProjectsDeleteResponse, ProjectsListRequest, ProjectsResponse, - }, - Client, -}; - -pub struct ClientProjects<'a> { - pub(crate) client: &'a mut crate::Client, -} - -impl<'a> ClientProjects<'a> { - pub async fn get(&mut self, input: &ProjectGetRequest) -> Result { - get_project(self.client, input).await - } - - pub async fn create(&mut self, input: &ProjectCreateRequest) -> Result { - create_project(self.client, input).await - } - - pub async fn list(&mut self, input: &ProjectsListRequest) -> Result { - list_projects(self.client, input).await - } - - pub async fn update(&mut self, input: &ProjectPutRequest) -> Result { - update_project(self.client, input).await - } - - pub async fn delete(&mut self, input: ProjectsDeleteRequest) -> Result { - delete_projects(self.client, input).await - } -} - -impl<'a> Client { - pub fn projects(&'a mut self) -> ClientProjects<'a> { - ClientProjects { client: self } - } -} diff --git a/crates/bitwarden-core/src/secrets_manager/client_secrets.rs b/crates/bitwarden-core/src/secrets_manager/client_secrets.rs deleted file mode 100644 index 6247c0856..000000000 --- a/crates/bitwarden-core/src/secrets_manager/client_secrets.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{ - error::Result, - secrets_manager::secrets::{ - create_secret, delete_secrets, get_secret, get_secrets_by_ids, list_secrets, - list_secrets_by_project, sync_secrets, update_secret, SecretCreateRequest, - SecretGetRequest, SecretIdentifiersByProjectRequest, SecretIdentifiersRequest, - SecretIdentifiersResponse, SecretPutRequest, SecretResponse, SecretsDeleteRequest, - SecretsDeleteResponse, SecretsGetRequest, SecretsResponse, SecretsSyncRequest, - SecretsSyncResponse, - }, - Client, -}; - -pub struct ClientSecrets<'a> { - pub(crate) client: &'a mut crate::Client, -} - -impl<'a> ClientSecrets<'a> { - pub async fn get(&mut self, input: &SecretGetRequest) -> Result { - get_secret(self.client, input).await - } - - pub async fn get_by_ids(&mut self, input: SecretsGetRequest) -> Result { - get_secrets_by_ids(self.client, input).await - } - - pub async fn create(&mut self, input: &SecretCreateRequest) -> Result { - create_secret(self.client, input).await - } - - pub async fn list( - &mut self, - input: &SecretIdentifiersRequest, - ) -> Result { - list_secrets(self.client, input).await - } - - pub async fn list_by_project( - &mut self, - input: &SecretIdentifiersByProjectRequest, - ) -> Result { - list_secrets_by_project(self.client, input).await - } - - pub async fn update(&mut self, input: &SecretPutRequest) -> Result { - update_secret(self.client, input).await - } - - pub async fn delete(&mut self, input: SecretsDeleteRequest) -> Result { - delete_secrets(self.client, input).await - } - - pub async fn sync(&mut self, input: &SecretsSyncRequest) -> Result { - sync_secrets(self.client, input).await - } -} - -impl<'a> Client { - pub fn secrets(&'a mut self) -> ClientSecrets<'a> { - ClientSecrets { client: self } - } -} diff --git a/crates/bitwarden-core/src/secrets_manager/mod.rs b/crates/bitwarden-core/src/secrets_manager/mod.rs index 181edf6b6..266c62acc 100644 --- a/crates/bitwarden-core/src/secrets_manager/mod.rs +++ b/crates/bitwarden-core/src/secrets_manager/mod.rs @@ -1,9 +1 @@ -pub mod projects; -pub mod secrets; pub mod state; - -mod client_projects; -mod client_secrets; - -pub use client_projects::ClientProjects; -pub use client_secrets::ClientSecrets; diff --git a/crates/bitwarden-json/src/client.rs b/crates/bitwarden-json/src/client.rs index 50565c904..c337eb7bd 100644 --- a/crates/bitwarden-json/src/client.rs +++ b/crates/bitwarden-json/src/client.rs @@ -7,6 +7,10 @@ use crate::{ command::Command, response::{Response, ResponseIntoString}, }; +#[cfg(feature = "secrets")] +use bitwarden::ClientProjectsExt; +#[cfg(feature = "secrets")] +use bitwarden::ClientSecretsExt; pub struct Client(Mutex); diff --git a/crates/bitwarden-sm/Cargo.toml b/crates/bitwarden-sm/Cargo.toml new file mode 100644 index 000000000..9af74d9aa --- /dev/null +++ b/crates/bitwarden-sm/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "bitwarden-sm" +description = """ +Internal crate for the bitwarden crate. Do not use. +""" + +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +homepage.workspace = true +repository.workspace = true +license-file.workspace = true +keywords.workspace = true + +[dependencies] +bitwarden-api-api = { workspace = true } +bitwarden-core = { workspace = true } +bitwarden-crypto = { workspace = true } +chrono = { version = ">=0.4.26, <0.5", features = [ + "clock", + "serde", + "std", +], default-features = false } +rand = ">=0.8.5, <0.9" +reqwest = { version = ">=0.12, <0.13", features = [ + "http2", + "json", +], default-features = false } +schemars = { version = ">=0.8.9, <0.9", features = ["uuid1", "chrono"] } +serde = { version = ">=1.0, <2.0", features = ["derive"] } +serde_json = ">=1.0.96, <2.0" +thiserror = ">=1.0.40, <2.0" +uniffi = { version = "=0.27.2", optional = true } +uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } + +[dev-dependencies] +rand_chacha = "0.3.1" +tokio = { version = "1.36.0", features = ["rt", "macros"] } +wiremock = "0.6.0" + +[lints] +workspace = true diff --git a/crates/bitwarden-sm/src/client_projects.rs b/crates/bitwarden-sm/src/client_projects.rs new file mode 100644 index 000000000..0c4a49d82 --- /dev/null +++ b/crates/bitwarden-sm/src/client_projects.rs @@ -0,0 +1,50 @@ +use bitwarden_core::{error::Error, Client}; + +use crate::projects::{ + create_project, delete_projects, get_project, list_projects, update_project, + ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectResponse, + ProjectsDeleteRequest, ProjectsDeleteResponse, ProjectsListRequest, ProjectsResponse, +}; + +pub struct ClientProjects<'a> { + pub client: &'a mut Client, +} + +impl<'a> ClientProjects<'a> { + pub fn new(client: &'a mut Client) -> Self { + Self { client } + } + + pub async fn get(&mut self, input: &ProjectGetRequest) -> Result { + get_project(self.client, input).await + } + + pub async fn create(&mut self, input: &ProjectCreateRequest) -> Result { + create_project(self.client, input).await + } + + pub async fn list(&mut self, input: &ProjectsListRequest) -> Result { + list_projects(self.client, input).await + } + + pub async fn update(&mut self, input: &ProjectPutRequest) -> Result { + update_project(self.client, input).await + } + + pub async fn delete( + &mut self, + input: ProjectsDeleteRequest, + ) -> Result { + delete_projects(self.client, input).await + } +} + +pub trait ClientProjectsExt<'a> { + fn projects(&'a mut self) -> ClientProjects<'a>; +} + +impl<'a> ClientProjectsExt<'a> for Client { + fn projects(&'a mut self) -> ClientProjects<'a> { + ClientProjects::new(self) + } +} diff --git a/crates/bitwarden-sm/src/client_secrets.rs b/crates/bitwarden-sm/src/client_secrets.rs new file mode 100644 index 000000000..7b0984ae1 --- /dev/null +++ b/crates/bitwarden-sm/src/client_secrets.rs @@ -0,0 +1,70 @@ +use bitwarden_core::{error::Error, Client}; + +use crate::secrets::{ + create_secret, delete_secrets, get_secret, get_secrets_by_ids, list_secrets, + list_secrets_by_project, sync_secrets, update_secret, SecretCreateRequest, SecretGetRequest, + SecretIdentifiersByProjectRequest, SecretIdentifiersRequest, SecretIdentifiersResponse, + SecretPutRequest, SecretResponse, SecretsDeleteRequest, SecretsDeleteResponse, + SecretsGetRequest, SecretsResponse, SecretsSyncRequest, SecretsSyncResponse, +}; + +pub struct ClientSecrets<'a> { + client: &'a mut Client, +} + +impl<'a> ClientSecrets<'a> { + pub fn new(client: &'a mut Client) -> Self { + Self { client } + } + + pub async fn get(&mut self, input: &SecretGetRequest) -> Result { + get_secret(self.client, input).await + } + + pub async fn get_by_ids(&mut self, input: SecretsGetRequest) -> Result { + get_secrets_by_ids(self.client, input).await + } + + pub async fn create(&mut self, input: &SecretCreateRequest) -> Result { + create_secret(self.client, input).await + } + + pub async fn list( + &mut self, + input: &SecretIdentifiersRequest, + ) -> Result { + list_secrets(self.client, input).await + } + + pub async fn list_by_project( + &mut self, + input: &SecretIdentifiersByProjectRequest, + ) -> Result { + list_secrets_by_project(self.client, input).await + } + + pub async fn update(&mut self, input: &SecretPutRequest) -> Result { + update_secret(self.client, input).await + } + + pub async fn delete( + &mut self, + input: SecretsDeleteRequest, + ) -> Result { + delete_secrets(self.client, input).await + } + + pub async fn sync(&mut self, input: &SecretsSyncRequest) -> Result { + sync_secrets(self.client, input).await + } +} + +pub trait ClientSecretsExt<'a> { + fn secrets(&'a mut self) -> ClientSecrets<'a>; +} + +impl<'a> ClientSecretsExt<'a> for Client { + fn secrets(&'a mut self) -> ClientSecrets<'a> { + ClientSecrets::new(self) + } +} diff --git a/crates/bitwarden-sm/src/lib.rs b/crates/bitwarden-sm/src/lib.rs new file mode 100644 index 000000000..4338891c3 --- /dev/null +++ b/crates/bitwarden-sm/src/lib.rs @@ -0,0 +1,21 @@ +mod client_projects; +mod client_secrets; +pub mod projects; +pub mod secrets; + +pub use client_projects::ClientProjectsExt; +pub use client_secrets::ClientSecretsExt; + +macro_rules! require { + ($val:expr) => { + match $val { + Some(val) => val, + None => { + return Err(bitwarden_core::error::Error::MissingFields(stringify!( + $val + ))) + } + } + }; +} +pub(crate) use require; diff --git a/crates/bitwarden-core/src/secrets_manager/projects/create.rs b/crates/bitwarden-sm/src/projects/create.rs similarity index 92% rename from crates/bitwarden-core/src/secrets_manager/projects/create.rs rename to crates/bitwarden-sm/src/projects/create.rs index ab3b7bd62..dda8af28d 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/create.rs +++ b/crates/bitwarden-sm/src/projects/create.rs @@ -1,14 +1,11 @@ use bitwarden_api_api::models::ProjectCreateRequestModel; +use bitwarden_core::{error::Error, Client}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{ - client::Client, - error::{Error, Result}, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -22,7 +19,7 @@ pub struct ProjectCreateRequest { pub(crate) async fn create_project( client: &mut Client, input: &ProjectCreateRequest, -) -> Result { +) -> Result { let key = client .get_encryption_settings()? .get_key(&Some(input.organization_id)) diff --git a/crates/bitwarden-core/src/secrets_manager/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs similarity index 96% rename from crates/bitwarden-core/src/secrets_manager/projects/delete.rs rename to crates/bitwarden-sm/src/projects/delete.rs index 05c808c7e..63b36369d 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -5,10 +5,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ - client::Client, - error::{require, Result}, -}; +use bitwarden_core::{client::Client, error::Result}; + +use crate::require; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs similarity index 92% rename from crates/bitwarden-core/src/secrets_manager/projects/get.rs rename to crates/bitwarden-sm/src/projects/get.rs index 00afaa194..33a60c974 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{client::Client, error::Result}; +use bitwarden_core::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs similarity index 98% rename from crates/bitwarden-core/src/secrets_manager/projects/list.rs rename to crates/bitwarden-sm/src/projects/list.rs index 5c491e14b..5eb3d36de 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/list.rs +++ b/crates/bitwarden-sm/src/projects/list.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{ +use bitwarden_core::{ client::{encryption_settings::EncryptionSettings, Client}, error::Result, }; diff --git a/crates/bitwarden-core/src/secrets_manager/projects/mod.rs b/crates/bitwarden-sm/src/projects/mod.rs similarity index 100% rename from crates/bitwarden-core/src/secrets_manager/projects/mod.rs rename to crates/bitwarden-sm/src/projects/mod.rs diff --git a/crates/bitwarden-core/src/secrets_manager/projects/project_response.rs b/crates/bitwarden-sm/src/projects/project_response.rs similarity index 92% rename from crates/bitwarden-core/src/secrets_manager/projects/project_response.rs rename to crates/bitwarden-sm/src/projects/project_response.rs index bf56f2006..19a84b9e7 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/project_response.rs +++ b/crates/bitwarden-sm/src/projects/project_response.rs @@ -5,10 +5,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ - client::encryption_settings::EncryptionSettings, - error::{require, Result}, -}; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result}; + +use crate::require; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs similarity index 98% rename from crates/bitwarden-core/src/secrets_manager/projects/update.rs rename to crates/bitwarden-sm/src/projects/update.rs index e00609ff4..c070f54b3 100644 --- a/crates/bitwarden-core/src/secrets_manager/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{ +use bitwarden_core::{ client::Client, error::{Error, Result}, }; diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs similarity index 98% rename from crates/bitwarden-core/src/secrets_manager/secrets/create.rs rename to crates/bitwarden-sm/src/secrets/create.rs index 4f84223dc..b7f7e9525 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{ +use bitwarden_core::{ error::{Error, Result}, Client, }; diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs similarity index 96% rename from crates/bitwarden-core/src/secrets_manager/secrets/delete.rs rename to crates/bitwarden-sm/src/secrets/delete.rs index f3fe264e1..65b87a0a8 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -5,10 +5,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ - client::Client, - error::{require, Result}, -}; +use bitwarden_core::{client::Client, error::Result}; + +use crate::require; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs similarity index 93% rename from crates/bitwarden-core/src/secrets_manager/secrets/get.rs rename to crates/bitwarden-sm/src/secrets/get.rs index 622253a55..4765cdbe1 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{error::Result, Client}; +use bitwarden_core::{error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs similarity index 94% rename from crates/bitwarden-core/src/secrets_manager/secrets/get_by_ids.rs rename to crates/bitwarden-sm/src/secrets/get_by_ids.rs index 032962849..46e4983bc 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/get_by_ids.rs +++ b/crates/bitwarden-sm/src/secrets/get_by_ids.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretsResponse; -use crate::{client::Client, error::Result}; +use bitwarden_core::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs similarity index 98% rename from crates/bitwarden-core/src/secrets_manager/secrets/list.rs rename to crates/bitwarden-sm/src/secrets/list.rs index b2473dd88..366de4296 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -6,11 +6,13 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ +use bitwarden_core::{ client::{encryption_settings::EncryptionSettings, Client}, - error::{require, Result}, + error::Result, }; +use crate::require; + #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretIdentifiersRequest { diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/mod.rs b/crates/bitwarden-sm/src/secrets/mod.rs similarity index 100% rename from crates/bitwarden-core/src/secrets_manager/secrets/mod.rs rename to crates/bitwarden-sm/src/secrets/mod.rs diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/secret_response.rs b/crates/bitwarden-sm/src/secrets/secret_response.rs similarity index 96% rename from crates/bitwarden-core/src/secrets_manager/secrets/secret_response.rs rename to crates/bitwarden-sm/src/secrets/secret_response.rs index 6f7446362..a4d9466d4 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/secret_response.rs +++ b/crates/bitwarden-sm/src/secrets/secret_response.rs @@ -7,10 +7,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ - client::encryption_settings::EncryptionSettings, - error::{require, Result}, -}; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result}; + +use crate::require; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs similarity index 94% rename from crates/bitwarden-core/src/secrets_manager/secrets/sync.rs rename to crates/bitwarden-sm/src/secrets/sync.rs index e2546022d..53ebc815d 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -4,12 +4,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; +use crate::require; + use super::SecretResponse; -use crate::{ - client::encryption_settings::EncryptionSettings, - error::{require, Result}, - Client, -}; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/secrets_manager/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs similarity index 98% rename from crates/bitwarden-core/src/secrets_manager/secrets/update.rs rename to crates/bitwarden-sm/src/secrets/update.rs index f9e54f810..9754207d8 100644 --- a/crates/bitwarden-core/src/secrets_manager/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{ +use bitwarden_core::{ client::Client, error::{Error, Result}, }; diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 7aa65c6f3..20f56830a 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -30,7 +30,7 @@ mobile = [ "bitwarden-crypto/mobile", "bitwarden-generators/mobile", ] # Mobile-specific features -secrets = ["bitwarden-core/internal"] # Secrets manager API +secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API [dependencies] bitwarden-api-api = { workspace = true } @@ -39,6 +39,7 @@ bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } bitwarden-exporters = { workspace = true, optional = true } bitwarden-generators = { workspace = true, optional = true } +bitwarden-sm = { workspace = true, optional = true } [lints] workspace = true diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index c91bd1104..8d9ee9324 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -1,4 +1,5 @@ pub use bitwarden_core::*; + #[cfg(feature = "internal")] pub use bitwarden_generators::ClientGeneratorExt; #[cfg(feature = "internal")] @@ -7,3 +8,17 @@ pub mod generators { PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, }; } + +#[cfg(feature = "secrets")] +pub use bitwarden_sm::ClientProjectsExt; +#[cfg(feature = "secrets")] +pub use bitwarden_sm::ClientSecretsExt; +#[cfg(feature = "secrets")] +pub mod secrets_manager { + pub mod projects { + pub use bitwarden_sm::projects::*; + } + pub mod secrets { + pub use bitwarden_sm::secrets::*; + } +} diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index eb5c8304b..21ce95e0c 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -13,6 +13,7 @@ use bitwarden::{ SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, }, }, + ClientProjectsExt, ClientSecretsExt, }; use bitwarden_cli::install_color_eyre; use clap::{CommandFactory, Parser}; From fba8dd8697da1f6f571163602fc8d548bca86eff Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 27 May 2024 11:37:21 +0200 Subject: [PATCH 04/28] Use a client wrapper --- Cargo.lock | 1 + .../src/tool/exporters/client_exporter.rs | 2 +- crates/bitwarden-json/src/client.rs | 6 +- crates/bitwarden-sm/src/lib.rs | 4 +- crates/bitwarden-uniffi/src/lib.rs | 2 +- crates/bitwarden-uniffi/src/tool/mod.rs | 1 - crates/bitwarden/Cargo.toml | 1 + crates/bitwarden/src/client.rs | 97 +++++++++++++++++++ crates/bitwarden/src/lib.rs | 11 +-- crates/bw/src/main.rs | 3 +- crates/bws/src/main.rs | 3 +- crates/sdk-schemas/src/main.rs | 2 +- 12 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 crates/bitwarden/src/client.rs diff --git a/Cargo.lock b/Cargo.lock index 75e0d58b3..0b8b4331a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,6 +375,7 @@ dependencies = [ "bitwarden-exporters", "bitwarden-generators", "bitwarden-sm", + "uuid", ] [[package]] diff --git a/crates/bitwarden-core/src/tool/exporters/client_exporter.rs b/crates/bitwarden-core/src/tool/exporters/client_exporter.rs index 05eb737f3..7efbc7fa3 100644 --- a/crates/bitwarden-core/src/tool/exporters/client_exporter.rs +++ b/crates/bitwarden-core/src/tool/exporters/client_exporter.rs @@ -6,7 +6,7 @@ use crate::{ }; pub struct ClientExporters<'a> { - pub(crate) client: &'a crate::Client, + client: &'a crate::Client, } impl<'a> ClientExporters<'a> { diff --git a/crates/bitwarden-json/src/client.rs b/crates/bitwarden-json/src/client.rs index c337eb7bd..15bf71372 100644 --- a/crates/bitwarden-json/src/client.rs +++ b/crates/bitwarden-json/src/client.rs @@ -1,5 +1,5 @@ use async_lock::Mutex; -use bitwarden::client::client_settings::ClientSettings; +use bitwarden::ClientSettings; #[cfg(feature = "secrets")] use crate::command::{ProjectsCommand, SecretsCommand}; @@ -7,10 +7,6 @@ use crate::{ command::Command, response::{Response, ResponseIntoString}, }; -#[cfg(feature = "secrets")] -use bitwarden::ClientProjectsExt; -#[cfg(feature = "secrets")] -use bitwarden::ClientSecretsExt; pub struct Client(Mutex); diff --git a/crates/bitwarden-sm/src/lib.rs b/crates/bitwarden-sm/src/lib.rs index 4338891c3..d2265c25b 100644 --- a/crates/bitwarden-sm/src/lib.rs +++ b/crates/bitwarden-sm/src/lib.rs @@ -3,8 +3,8 @@ mod client_secrets; pub mod projects; pub mod secrets; -pub use client_projects::ClientProjectsExt; -pub use client_secrets::ClientSecretsExt; +pub use client_projects::{ClientProjects, ClientProjectsExt}; +pub use client_secrets::{ClientSecrets, ClientSecretsExt}; macro_rules! require { ($val:expr) => { diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index 4f4c3b1b5..e0befebc5 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use async_lock::RwLock; use auth::ClientAuth; -use bitwarden::client::client_settings::ClientSettings; +use bitwarden::ClientSettings; pub mod auth; pub mod crypto; diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index 8043cf58f..1861bf373 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -5,7 +5,6 @@ use bitwarden::{ generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest}, tool::ExportFormat, vault::{Cipher, Collection, Folder}, - ClientGeneratorExt, }; use crate::{error::Result, Client}; diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 20f56830a..0ee4036df 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -40,6 +40,7 @@ bitwarden-crypto = { workspace = true } bitwarden-exporters = { workspace = true, optional = true } bitwarden-generators = { workspace = true, optional = true } bitwarden-sm = { workspace = true, optional = true } +uuid = ">=1.3.3, <2" [lints] workspace = true diff --git a/crates/bitwarden/src/client.rs b/crates/bitwarden/src/client.rs new file mode 100644 index 000000000..f46d1e07a --- /dev/null +++ b/crates/bitwarden/src/client.rs @@ -0,0 +1,97 @@ +use bitwarden_core::{ + auth::client_auth::ClientAuth, + client::client_settings::ClientSettings, + error::Error, + mobile::ClientKdf, + platform::{SyncRequest, SyncResponse}, +}; + +#[cfg(feature = "secrets")] +use bitwarden_sm::{ClientProjects, ClientProjectsExt, ClientSecrets, ClientSecretsExt}; + +#[cfg(feature = "mobile")] +use bitwarden_core::mobile::{vault::ClientVault, ClientCrypto}; + +#[cfg(feature = "internal")] +use bitwarden_core::{ + platform::{client_platform::ClientPlatform, SecretVerificationRequest, UserApiKeyResponse}, + tool::ClientExporters, +}; + +#[cfg(feature = "internal")] +use bitwarden_generators::{ClientGenerator, ClientGeneratorExt}; +use uuid::Uuid; + +pub struct Client(bitwarden_core::Client); + +impl Client { + pub fn new(settings: Option) -> Self { + Self(bitwarden_core::Client::new(settings)) + } + + #[cfg(feature = "internal")] + pub fn load_flags(&mut self, flags: std::collections::HashMap) { + self.0.load_flags(flags) + } + + pub fn get_access_token_organization(&self) -> Option { + self.0.get_access_token_organization() + } + + #[cfg(feature = "internal")] + pub async fn sync(&mut self, input: &SyncRequest) -> Result { + self.0.sync(input).await + } + + #[cfg(feature = "internal")] + pub async fn get_user_api_key( + &mut self, + input: SecretVerificationRequest, + ) -> Result { + self.0.get_user_api_key(input).await + } + + #[cfg(feature = "mobile")] + pub fn kdf(&self) -> ClientKdf { + self.0.kdf() + } + + pub fn auth(&mut self) -> ClientAuth { + self.0.auth() + } + + #[cfg(feature = "mobile")] + pub fn vault(&self) -> ClientVault { + self.0.vault() + } + + #[cfg(feature = "internal")] + pub fn platform(&mut self) -> ClientPlatform { + self.0.platform() + } + + #[cfg(feature = "internal")] + pub fn generator(&self) -> ClientGenerator { + self.0.generator() + } + + #[cfg(feature = "internal")] + pub fn exporters(&self) -> ClientExporters { + self.0.exporters() + } + + #[cfg(feature = "mobile")] + pub fn crypto(&mut self) -> ClientCrypto { + self.0.crypto() + } + + #[cfg(feature = "secrets")] + pub fn secrets(&mut self) -> ClientSecrets { + self.0.secrets() + } + + #[cfg(feature = "secrets")] + pub fn projects(&mut self) -> ClientProjects { + self.0.projects() + } +} diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index 8d9ee9324..b51fa1f74 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -1,7 +1,10 @@ +#[allow(hidden_glob_reexports)] +mod client; +pub use client::Client; + +pub use bitwarden_core::client::client_settings::ClientSettings; pub use bitwarden_core::*; -#[cfg(feature = "internal")] -pub use bitwarden_generators::ClientGeneratorExt; #[cfg(feature = "internal")] pub mod generators { pub use bitwarden_generators::{ @@ -9,10 +12,6 @@ pub mod generators { }; } -#[cfg(feature = "secrets")] -pub use bitwarden_sm::ClientProjectsExt; -#[cfg(feature = "secrets")] -pub use bitwarden_sm::ClientSecretsExt; #[cfg(feature = "secrets")] pub mod secrets_manager { pub mod projects { diff --git a/crates/bw/src/main.rs b/crates/bw/src/main.rs index 90998655b..f5c35afa6 100644 --- a/crates/bw/src/main.rs +++ b/crates/bw/src/main.rs @@ -1,8 +1,7 @@ use bitwarden::{ auth::RegisterRequest, - client::client_settings::ClientSettings, generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, - ClientGeneratorExt, + ClientSettings, }; use bitwarden_cli::{install_color_eyre, text_prompt_when_none, Color}; use bitwarden_crypto::SensitiveString; diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 21ce95e0c..7b35b809d 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -2,7 +2,6 @@ use std::{path::PathBuf, process, str::FromStr}; use bitwarden::{ auth::{login::AccessTokenLoginRequest, AccessToken}, - client::client_settings::ClientSettings, secrets_manager::{ projects::{ ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsDeleteRequest, @@ -13,7 +12,7 @@ use bitwarden::{ SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, }, }, - ClientProjectsExt, ClientSecretsExt, + ClientSettings, }; use bitwarden_cli::install_color_eyre; use clap::{CommandFactory, Parser}; diff --git a/crates/sdk-schemas/src/main.rs b/crates/sdk-schemas/src/main.rs index de57b0b17..8348798a1 100644 --- a/crates/sdk-schemas/src/main.rs +++ b/crates/sdk-schemas/src/main.rs @@ -91,7 +91,7 @@ use bitwarden_json::response::Response; #[derive(JsonSchema)] struct SchemaTypes { // Input types for new Client - client_settings: bitwarden::client::client_settings::ClientSettings, + client_settings: bitwarden::ClientSettings, // Input types for Client::run_command input_command: bitwarden_json::command::Command, From 66d191d4c045700a8e37658235176a32f92e7975 Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 6 Jun 2024 10:38:45 +0200 Subject: [PATCH 05/28] Create bitwarden-send crate --- Cargo.lock | 18 ++ Cargo.toml | 1 + crates/bitwarden-core/src/error.rs | 1 + crates/bitwarden-core/src/lib.rs | 34 ++-- crates/bitwarden-core/src/platform/domain.rs | 23 --- crates/bitwarden-core/src/platform/sync.rs | 154 ------------------ crates/bitwarden-core/src/tool/mod.rs | 4 - crates/bitwarden-core/src/vault/sync.rs | 4 +- crates/bitwarden-core/tests/register.rs | 2 +- crates/bitwarden-json/src/client.rs | 2 + crates/bitwarden-send/Cargo.toml | 37 +++++ crates/bitwarden-send/README.md | 6 + .../src}/client_sends.rs | 24 ++- crates/bitwarden-send/src/lib.rs | 10 ++ .../src/tool => bitwarden-send/src}/send.rs | 11 +- crates/bitwarden-send/src/uniffi_support.rs | 8 + crates/bitwarden-sm/src/lib.rs | 14 -- crates/bitwarden-sm/src/projects/delete.rs | 5 +- crates/bitwarden-sm/src/projects/get.rs | 2 +- crates/bitwarden-sm/src/projects/list.rs | 8 +- .../src/projects/project_response.rs | 5 +- crates/bitwarden-sm/src/projects/update.rs | 8 +- crates/bitwarden-sm/src/secrets/create.rs | 8 +- crates/bitwarden-sm/src/secrets/delete.rs | 5 +- crates/bitwarden-sm/src/secrets/get.rs | 2 +- crates/bitwarden-sm/src/secrets/get_by_ids.rs | 2 +- crates/bitwarden-sm/src/secrets/list.rs | 12 +- .../src/secrets/secret_response.rs | 5 +- crates/bitwarden-sm/src/secrets/sync.rs | 6 +- crates/bitwarden-sm/src/secrets/update.rs | 8 +- crates/bitwarden-uniffi/src/docs.rs | 3 +- crates/bitwarden-uniffi/src/tool/mod.rs | 5 +- crates/bitwarden-uniffi/src/tool/sends.rs | 2 +- crates/bitwarden/Cargo.toml | 3 + crates/bitwarden/src/client.rs | 85 ---------- crates/bitwarden/src/lib.rs | 26 ++- crates/bw/src/main.rs | 2 +- crates/bws/src/main.rs | 1 + 38 files changed, 180 insertions(+), 376 deletions(-) delete mode 100644 crates/bitwarden-core/src/platform/domain.rs delete mode 100644 crates/bitwarden-core/src/platform/sync.rs create mode 100644 crates/bitwarden-send/Cargo.toml create mode 100644 crates/bitwarden-send/README.md rename crates/{bitwarden-core/src/tool => bitwarden-send/src}/client_sends.rs (87%) create mode 100644 crates/bitwarden-send/src/lib.rs rename crates/{bitwarden-core/src/tool => bitwarden-send/src}/send.rs (99%) create mode 100644 crates/bitwarden-send/src/uniffi_support.rs delete mode 100644 crates/bitwarden/src/client.rs diff --git a/Cargo.lock b/Cargo.lock index eb209b320..35db76950 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -380,6 +380,7 @@ dependencies = [ "bitwarden-crypto", "bitwarden-exporters", "bitwarden-generators", + "bitwarden-send", "bitwarden-sm", "uuid", ] @@ -566,6 +567,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "bitwarden-send" +version = "0.5.0" +dependencies = [ + "base64 0.21.7", + "bitwarden-api-api", + "bitwarden-core", + "bitwarden-crypto", + "chrono", + "schemars", + "serde", + "serde_repr", + "uniffi", + "uuid", + "zeroize", +] + [[package]] name = "bitwarden-sm" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index be359da0c..eb0fcd8e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ bitwarden-core = { path = "crates/bitwarden-core", version = "=0.5.0" } bitwarden-crypto = { path = "crates/bitwarden-crypto", version = "=0.5.0" } bitwarden-exporters = { path = "crates/bitwarden-exporters", version = "=0.5.0" } bitwarden-generators = { path = "crates/bitwarden-generators", version = "=0.5.0" } +bitwarden-send = { path = "crates/bitwarden-send", version = "=0.5.0" } bitwarden-sm = { path = "crates/bitwarden-sm", version = "=0.5.0" } [workspace.lints.clippy] diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index 68fc9d0d5..5f0b0f7d9 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -145,6 +145,7 @@ impl_bitwarden_error!(IdentityError); /// It is equivalent to using `val.ok_or(Error::MissingFields)?`, but easier to use and /// with a more descriptive error message. /// Note that this macro will return early from the function if the value is not present. +#[macro_export] macro_rules! require { ($val:expr) => { match $val { diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index 33a2895d1..e892e3935 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -16,11 +16,8 @@ //! //! ```rust //! use bitwarden::{ -//! auth::login::AccessTokenLoginRequest, -//! client::client_settings::{ClientSettings, DeviceType}, -//! error::Result, -//! secrets_manager::secrets::SecretIdentifiersRequest, -//! Client, +//! auth::login::AccessTokenLoginRequest, error::Result, +//! secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, //! }; //! use uuid::Uuid; //! @@ -38,15 +35,27 @@ //! let mut client = Client::new(Some(settings)); //! //! // Before we operate, we need to authenticate with a token -//! let token = AccessTokenLoginRequest { access_token: String::from(""), state_file: None }; +//! let token = AccessTokenLoginRequest { +//! access_token: String::from(""), +//! state_file: None, +//! }; //! client.auth().login_access_token(&token).await.unwrap(); //! -//! let org_id = SecretIdentifiersRequest { organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap() }; -//! println!("Stored secrets: {:#?}", client.secrets().list(&org_id).await.unwrap()); +//! let org_id = SecretIdentifiersRequest { +//! organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), +//! }; +//! println!( +//! "Stored secrets: {:#?}", +//! client.secrets().list(&org_id).await.unwrap() +//! ); //! Ok(()) //! } //! ``` +// Ensure the readme docs compile +#[doc = include_str!("../README.md")] +mod readme {} + #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); @@ -63,16 +72,11 @@ pub mod platform; pub mod secrets_manager; #[cfg(feature = "internal")] pub mod tool; -#[cfg(feature = "internal")] +#[cfg(feature = "uniffi")] pub(crate) mod uniffi_support; mod util; #[cfg(feature = "internal")] pub mod vault; -pub use client::Client; - -// Ensure the readme docs compile -#[doc = include_str!("../README.md")] -mod readme {} - pub use bitwarden_crypto::ZeroizingAllocator; +pub use client::{Client, ClientSettings, DeviceType}; diff --git a/crates/bitwarden-core/src/platform/domain.rs b/crates/bitwarden-core/src/platform/domain.rs deleted file mode 100644 index 482cb1f59..000000000 --- a/crates/bitwarden-core/src/platform/domain.rs +++ /dev/null @@ -1,23 +0,0 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use crate::error::{require, Error, Result}; - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -pub struct GlobalDomains { - pub r#type: i32, - pub domains: Vec, - pub excluded: bool, -} - -impl TryFrom for GlobalDomains { - type Error = Error; - - fn try_from(global_domains: bitwarden_api_api::models::GlobalDomains) -> Result { - Ok(Self { - r#type: require!(global_domains.r#type), - domains: require!(global_domains.domains), - excluded: require!(global_domains.excluded), - }) - } -} diff --git a/crates/bitwarden-core/src/platform/sync.rs b/crates/bitwarden-core/src/platform/sync.rs deleted file mode 100644 index bd9d38104..000000000 --- a/crates/bitwarden-core/src/platform/sync.rs +++ /dev/null @@ -1,154 +0,0 @@ -use bitwarden_api_api::models::{ - DomainsResponseModel, ProfileOrganizationResponseModel, ProfileResponseModel, SyncResponseModel, -}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use super::domain::GlobalDomains; -use crate::{ - admin_console::Policy, - client::{encryption_settings::EncryptionSettings, Client}, - error::{require, Error, Result}, - vault::{Cipher, Collection, Folder}, -}; - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct SyncRequest { - /// Exclude the subdomains from the response, defaults to false - pub exclude_subdomains: Option, -} - -pub(crate) async fn sync(client: &mut 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?; - - let org_keys: Vec<_> = require!(sync.profile.as_ref()) - .organizations - .as_deref() - .unwrap_or_default() - .iter() - .filter_map(|o| o.id.zip(o.key.as_deref().and_then(|k| k.parse().ok()))) - .collect(); - - let enc = client.initialize_org_crypto(org_keys)?; - - SyncResponse::process_response(sync, enc) -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct ProfileResponse { - pub id: Uuid, - pub name: String, - pub email: String, - - //key: String, - //private_key: String, - pub organizations: Vec, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct ProfileOrganizationResponse { - pub id: Uuid, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct DomainResponse { - pub equivalent_domains: Vec>, - pub global_equivalent_domains: Vec, -} - -#[derive(Serialize, Deserialize, Debug, JsonSchema)] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct SyncResponse { - /// Data about the user, including their encryption keys and the organizations they are a part - /// of - pub profile: ProfileResponse, - pub folders: Vec, - pub collections: Vec, - /// List of ciphers accessible by the user - pub ciphers: Vec, - pub domains: Option, - pub policies: Vec, - pub sends: Vec, -} - -impl SyncResponse { - pub(crate) fn process_response( - response: SyncResponseModel, - enc: &EncryptionSettings, - ) -> Result { - let profile = require!(response.profile); - let ciphers = require!(response.ciphers); - - fn try_into_iter(iter: In) -> Result - where - In: IntoIterator, - InItem: TryInto, - Out: FromIterator, - { - iter.into_iter().map(|i| i.try_into()).collect() - } - - Ok(SyncResponse { - profile: ProfileResponse::process_response(*profile, enc)?, - folders: try_into_iter(require!(response.folders))?, - collections: try_into_iter(require!(response.collections))?, - ciphers: try_into_iter(ciphers)?, - domains: response.domains.map(|d| (*d).try_into()).transpose()?, - policies: try_into_iter(require!(response.policies))?, - sends: try_into_iter(require!(response.sends))?, - }) - } -} - -impl ProfileOrganizationResponse { - fn process_response( - response: ProfileOrganizationResponseModel, - ) -> Result { - Ok(ProfileOrganizationResponse { - id: require!(response.id), - }) - } -} - -impl ProfileResponse { - fn process_response( - response: ProfileResponseModel, - _enc: &EncryptionSettings, - ) -> Result { - Ok(ProfileResponse { - id: require!(response.id), - name: require!(response.name), - email: require!(response.email), - //key: response.key, - //private_key: response.private_key, - organizations: response - .organizations - .unwrap_or_default() - .into_iter() - .map(ProfileOrganizationResponse::process_response) - .collect::>()?, - }) - } -} - -impl TryFrom for DomainResponse { - type Error = Error; - fn try_from(value: DomainsResponseModel) -> Result { - Ok(Self { - equivalent_domains: value.equivalent_domains.unwrap_or_default(), - global_equivalent_domains: value - .global_equivalent_domains - .unwrap_or_default() - .into_iter() - .map(|s| s.try_into()) - .collect::>>()?, - }) - } -} diff --git a/crates/bitwarden-core/src/tool/mod.rs b/crates/bitwarden-core/src/tool/mod.rs index 59cc7c62d..8034151d7 100644 --- a/crates/bitwarden-core/src/tool/mod.rs +++ b/crates/bitwarden-core/src/tool/mod.rs @@ -1,6 +1,2 @@ mod exporters; pub use exporters::{ClientExporters, ExportFormat}; -mod send; -pub use send::{Send, SendListView, SendView}; -mod client_sends; -pub use client_sends::ClientSends; diff --git a/crates/bitwarden-core/src/vault/sync.rs b/crates/bitwarden-core/src/vault/sync.rs index bd9d38104..792004931 100644 --- a/crates/bitwarden-core/src/vault/sync.rs +++ b/crates/bitwarden-core/src/vault/sync.rs @@ -75,7 +75,7 @@ pub struct SyncResponse { pub ciphers: Vec, pub domains: Option, pub policies: Vec, - pub sends: Vec, + //pub sends: Vec, } impl SyncResponse { @@ -102,7 +102,7 @@ impl SyncResponse { ciphers: try_into_iter(ciphers)?, domains: response.domains.map(|d| (*d).try_into()).transpose()?, policies: try_into_iter(require!(response.policies))?, - sends: try_into_iter(require!(response.sends))?, + //sends: try_into_iter(require!(response.sends))?, }) } } diff --git a/crates/bitwarden-core/tests/register.rs b/crates/bitwarden-core/tests/register.rs index 7a0c964fd..adb918c64 100644 --- a/crates/bitwarden-core/tests/register.rs +++ b/crates/bitwarden-core/tests/register.rs @@ -4,7 +4,7 @@ async fn test_register_initialize_crypto() { use std::num::NonZeroU32; - use bitwarden::{ + use bitwarden_core::{ mobile::crypto::{InitUserCryptoMethod, InitUserCryptoRequest}, Client, }; diff --git a/crates/bitwarden-json/src/client.rs b/crates/bitwarden-json/src/client.rs index 037e5842c..b138bc754 100644 --- a/crates/bitwarden-json/src/client.rs +++ b/crates/bitwarden-json/src/client.rs @@ -1,4 +1,6 @@ use async_lock::Mutex; +#[cfg(feature = "secrets")] +use bitwarden::secrets_manager::{ClientProjectsExt, ClientSecretsExt}; use bitwarden::ClientSettings; #[cfg(feature = "secrets")] diff --git a/crates/bitwarden-send/Cargo.toml b/crates/bitwarden-send/Cargo.toml new file mode 100644 index 000000000..a20b08c57 --- /dev/null +++ b/crates/bitwarden-send/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "bitwarden-send" +description = """ +Internal crate for the bitwarden crate. Do not use. +""" + +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +homepage.workspace = true +repository.workspace = true +license-file.workspace = true +keywords.workspace = true + +[features] +uniffi = ["dep:uniffi"] # Uniffi bindings + +[dependencies] +base64 = ">=0.21.2, <0.23" +bitwarden-api-api = { workspace = true } +bitwarden-core = { workspace = true } +bitwarden-crypto = { workspace = true } +chrono = { version = ">=0.4.26, <0.5", features = [ + "clock", + "serde", + "std", +], default-features = false } +schemars = { version = ">=0.8.9, <0.9", features = ["uuid1", "chrono"] } +serde = { version = ">=1.0, <2.0", features = ["derive"] } +serde_repr = ">=0.1.12, <0.2" +uniffi = { version = "=0.27.2", optional = true } +uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } +zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } + +[lints] +workspace = true diff --git a/crates/bitwarden-send/README.md b/crates/bitwarden-send/README.md new file mode 100644 index 000000000..85da845b4 --- /dev/null +++ b/crates/bitwarden-send/README.md @@ -0,0 +1,6 @@ +# Bitwarden Send + +This is an internal crate for the Bitwarden SDK do not depend on this directly and use the +[`bitwarden`](https://crates.io/crates/bitwarden) crate instead. + +This crate does not follow semantic versioning and the public interface may change at any time. diff --git a/crates/bitwarden-core/src/tool/client_sends.rs b/crates/bitwarden-send/src/client_sends.rs similarity index 87% rename from crates/bitwarden-core/src/tool/client_sends.rs rename to crates/bitwarden-send/src/client_sends.rs index f98027974..2833e1881 100644 --- a/crates/bitwarden-core/src/tool/client_sends.rs +++ b/crates/bitwarden-send/src/client_sends.rs @@ -1,18 +1,22 @@ use std::path::Path; -use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable}; - -use crate::{ +use bitwarden_core::{ error::{Error, Result}, - tool::{Send, SendListView, SendView}, Client, }; +use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable}; + +use crate::{Send, SendListView, SendView}; pub struct ClientSends<'a> { - pub(crate) client: &'a Client, + client: &'a Client, } impl<'a> ClientSends<'a> { + fn new(client: &'a Client) -> Self { + Self { client } + } + pub async fn decrypt(&self, send: Send) -> Result { let enc = self.client.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; @@ -86,8 +90,12 @@ impl<'a> ClientSends<'a> { } } -impl<'a> Client { - pub fn sends(&'a mut self) -> ClientSends<'a> { - ClientSends { client: self } +pub trait ClientSendsExt<'a> { + fn sends(&'a self) -> ClientSends<'a>; +} + +impl<'a> ClientSendsExt<'a> for Client { + fn sends(&'a self) -> ClientSends<'a> { + ClientSends::new(self) } } diff --git a/crates/bitwarden-send/src/lib.rs b/crates/bitwarden-send/src/lib.rs new file mode 100644 index 000000000..a8a8c4540 --- /dev/null +++ b/crates/bitwarden-send/src/lib.rs @@ -0,0 +1,10 @@ +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!(); + +mod client_sends; +pub use client_sends::{ClientSends, ClientSendsExt}; +mod send; +pub use send::{Send, SendListView, SendView}; + +#[cfg(feature = "uniffi")] +mod uniffi_support; diff --git a/crates/bitwarden-core/src/tool/send.rs b/crates/bitwarden-send/src/send.rs similarity index 99% rename from crates/bitwarden-core/src/tool/send.rs rename to crates/bitwarden-send/src/send.rs index 2ce83dd0a..2a7cb2ac3 100644 --- a/crates/bitwarden-core/src/tool/send.rs +++ b/crates/bitwarden-send/src/send.rs @@ -3,6 +3,10 @@ use base64::{ Engine, }; use bitwarden_api_api::models::{SendFileModel, SendResponseModel, SendTextModel}; +use bitwarden_core::{ + error::{Error, Result}, + require, +}; use bitwarden_crypto::{ derive_shareable_key, generate_random_bytes, CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, @@ -14,8 +18,6 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; use zeroize::Zeroizing; -use crate::error::{require, Error, Result}; - const SEND_ITERATIONS: u32 = 100_000; #[derive(Serialize, Deserialize, Debug, JsonSchema)] @@ -360,13 +362,10 @@ impl TryFrom for SendText { #[cfg(test)] mod tests { + use bitwarden_core::client::{encryption_settings::EncryptionSettings, Kdf}; use bitwarden_crypto::{KeyDecryptable, KeyEncryptable, MasterKey}; use super::{Send, SendText, SendTextView, SendType}; - use crate::{ - client::{encryption_settings::EncryptionSettings, Kdf}, - tool::SendView, - }; #[test] fn test_get_send_key() { diff --git a/crates/bitwarden-send/src/uniffi_support.rs b/crates/bitwarden-send/src/uniffi_support.rs new file mode 100644 index 000000000..90cc58855 --- /dev/null +++ b/crates/bitwarden-send/src/uniffi_support.rs @@ -0,0 +1,8 @@ +use bitwarden_crypto::EncString; +use uuid::Uuid; + +// Forward the type definitions to the main bitwarden crate +type DateTime = chrono::DateTime; +uniffi::ffi_converter_forward!(DateTime, bitwarden_core::UniFfiTag, crate::UniFfiTag); +uniffi::ffi_converter_forward!(EncString, bitwarden_crypto::UniFfiTag, crate::UniFfiTag); +uniffi::ffi_converter_forward!(Uuid, bitwarden_core::UniFfiTag, crate::UniFfiTag); diff --git a/crates/bitwarden-sm/src/lib.rs b/crates/bitwarden-sm/src/lib.rs index d2265c25b..6f44bd16d 100644 --- a/crates/bitwarden-sm/src/lib.rs +++ b/crates/bitwarden-sm/src/lib.rs @@ -5,17 +5,3 @@ pub mod secrets; pub use client_projects::{ClientProjects, ClientProjectsExt}; pub use client_secrets::{ClientSecrets, ClientSecretsExt}; - -macro_rules! require { - ($val:expr) => { - match $val { - Some(val) => val, - None => { - return Err(bitwarden_core::error::Error::MissingFields(stringify!( - $val - ))) - } - } - }; -} -pub(crate) use require; diff --git a/crates/bitwarden-sm/src/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs index 63b36369d..34e82feae 100644 --- a/crates/bitwarden-sm/src/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -1,14 +1,11 @@ use bitwarden_api_api::models::{ BulkDeleteResponseModel, BulkDeleteResponseModelListResponseModel, }; +use bitwarden_core::{client::Client, error::Result, require}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use bitwarden_core::{client::Client, error::Result}; - -use crate::require; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProjectsDeleteRequest { diff --git a/crates/bitwarden-sm/src/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs index 33a60c974..4098f19df 100644 --- a/crates/bitwarden-sm/src/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -1,9 +1,9 @@ +use bitwarden_core::{client::Client, error::Result}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use bitwarden_core::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs index 5eb3d36de..16c4501e1 100644 --- a/crates/bitwarden-sm/src/projects/list.rs +++ b/crates/bitwarden-sm/src/projects/list.rs @@ -1,13 +1,13 @@ use bitwarden_api_api::models::ProjectResponseModelListResponseModel; +use bitwarden_core::{ + client::{encryption_settings::EncryptionSettings, Client}, + error::Result, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use bitwarden_core::{ - client::{encryption_settings::EncryptionSettings, Client}, - error::Result, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/projects/project_response.rs b/crates/bitwarden-sm/src/projects/project_response.rs index 1e5e4536b..4e129c73a 100644 --- a/crates/bitwarden-sm/src/projects/project_response.rs +++ b/crates/bitwarden-sm/src/projects/project_response.rs @@ -1,14 +1,11 @@ use bitwarden_api_api::models::ProjectResponseModel; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result, require}; use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result}; - -use crate::require; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProjectResponse { diff --git a/crates/bitwarden-sm/src/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs index c070f54b3..b5249a2ff 100644 --- a/crates/bitwarden-sm/src/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -1,14 +1,14 @@ use bitwarden_api_api::models::ProjectUpdateRequestModel; +use bitwarden_core::{ + client::Client, + error::{Error, Result}, +}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use bitwarden_core::{ - client::Client, - error::{Error, Result}, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs index b7f7e9525..50a6fe2ca 100644 --- a/crates/bitwarden-sm/src/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -1,14 +1,14 @@ use bitwarden_api_api::models::SecretCreateRequestModel; +use bitwarden_core::{ + error::{Error, Result}, + Client, +}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use bitwarden_core::{ - error::{Error, Result}, - Client, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs index 65b87a0a8..028f2c53a 100644 --- a/crates/bitwarden-sm/src/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -1,14 +1,11 @@ use bitwarden_api_api::models::{ BulkDeleteResponseModel, BulkDeleteResponseModelListResponseModel, }; +use bitwarden_core::{client::Client, error::Result, require}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use bitwarden_core::{client::Client, error::Result}; - -use crate::require; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretsDeleteRequest { diff --git a/crates/bitwarden-sm/src/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs index 4765cdbe1..008040d64 100644 --- a/crates/bitwarden-sm/src/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -1,9 +1,9 @@ +use bitwarden_core::{error::Result, Client}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use bitwarden_core::{error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs index 46e4983bc..50a7612a9 100644 --- a/crates/bitwarden-sm/src/secrets/get_by_ids.rs +++ b/crates/bitwarden-sm/src/secrets/get_by_ids.rs @@ -1,10 +1,10 @@ use bitwarden_api_api::models::GetSecretsRequestModel; +use bitwarden_core::{client::Client, error::Result}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretsResponse; -use bitwarden_core::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs index 394b14148..73ca2e5c3 100644 --- a/crates/bitwarden-sm/src/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -1,17 +1,15 @@ use bitwarden_api_api::models::{ SecretWithProjectsListResponseModel, SecretsWithProjectsInnerSecret, }; -use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - use bitwarden_core::{ client::{encryption_settings::EncryptionSettings, Client}, error::Result, + require, }; - -use crate::require; +use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/secret_response.rs b/crates/bitwarden-sm/src/secrets/secret_response.rs index 1ff552e1c..829dc4c14 100644 --- a/crates/bitwarden-sm/src/secrets/secret_response.rs +++ b/crates/bitwarden-sm/src/secrets/secret_response.rs @@ -1,16 +1,13 @@ use bitwarden_api_api::models::{ BaseSecretResponseModel, BaseSecretResponseModelListResponseModel, SecretResponseModel, }; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result, require}; use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result}; - -use crate::require; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretResponse { diff --git a/crates/bitwarden-sm/src/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs index 53ebc815d..61d526d12 100644 --- a/crates/bitwarden-sm/src/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -1,13 +1,13 @@ use bitwarden_api_api::models::SecretsSyncResponseModel; +use bitwarden_core::{ + client::encryption_settings::EncryptionSettings, error::Result, require, Client, +}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::require; - use super::SecretResponse; -use bitwarden_core::{client::encryption_settings::EncryptionSettings, error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-sm/src/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs index 9754207d8..e4bcaff1b 100644 --- a/crates/bitwarden-sm/src/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -1,14 +1,14 @@ use bitwarden_api_api::models::SecretUpdateRequestModel; +use bitwarden_core::{ + client::Client, + error::{Error, Result}, +}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use bitwarden_core::{ - client::Client, - error::{Error, Result}, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-uniffi/src/docs.rs b/crates/bitwarden-uniffi/src/docs.rs index 0569bbcb2..3d8cc95ee 100644 --- a/crates/bitwarden-uniffi/src/docs.rs +++ b/crates/bitwarden-uniffi/src/docs.rs @@ -3,7 +3,8 @@ use bitwarden::{ generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest}, platform::FingerprintRequest, - tool::{ExportFormat, Send, SendListView, SendView}, + send::{Send, SendListView, SendView}, + tool::ExportFormat, vault::{Cipher, CipherView, Collection, Folder, FolderView, TotpResponse}, }; use bitwarden_crypto::{HashPurpose, Kdf}; diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index 1ed5d33c2..ef2387e77 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -2,7 +2,10 @@ use std::sync::Arc; use bitwarden::{ error::Error, - generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest}, + generators::{ + ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest, + UsernameGeneratorRequest, + }, tool::ExportFormat, vault::{Cipher, Collection, Folder}, }; diff --git a/crates/bitwarden-uniffi/src/tool/sends.rs b/crates/bitwarden-uniffi/src/tool/sends.rs index e6aef3e51..75e6e6c4e 100644 --- a/crates/bitwarden-uniffi/src/tool/sends.rs +++ b/crates/bitwarden-uniffi/src/tool/sends.rs @@ -1,6 +1,6 @@ use std::{path::Path, sync::Arc}; -use bitwarden::tool::{Send, SendListView, SendView}; +use bitwarden::send::{ClientSendsExt, Send, SendListView, SendView}; use crate::{Client, Result}; diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 389d41a9c..2e87a7a3f 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -19,6 +19,7 @@ default = ["secrets"] internal = [ "dep:bitwarden-exporters", "dep:bitwarden-generators", + "dep:bitwarden-send", "bitwarden-core/internal", ] # Internal testing methods no-memory-hardening = [ @@ -28,6 +29,7 @@ uniffi = [ "bitwarden-core/uniffi", "bitwarden-crypto/uniffi", "bitwarden-generators/uniffi", + "bitwarden-send/uniffi", ] # Uniffi bindings secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API @@ -39,6 +41,7 @@ bitwarden-crypto = { workspace = true } bitwarden-exporters = { workspace = true, optional = true } bitwarden-generators = { workspace = true, optional = true } bitwarden-sm = { workspace = true, optional = true } +bitwarden-send = { workspace = true, optional = true } uuid = ">=1.3.3, <2" [lints] diff --git a/crates/bitwarden/src/client.rs b/crates/bitwarden/src/client.rs deleted file mode 100644 index 6386aa6ae..000000000 --- a/crates/bitwarden/src/client.rs +++ /dev/null @@ -1,85 +0,0 @@ -use bitwarden_core::{ - auth::client_auth::ClientAuth, client::client_settings::ClientSettings, mobile::ClientKdf, -}; - -#[cfg(feature = "secrets")] -use bitwarden_sm::{ClientProjects, ClientProjectsExt, ClientSecrets, ClientSecretsExt}; - -#[cfg(feature = "uniffi")] -use bitwarden_core::mobile::ClientCrypto; - -#[cfg(feature = "internal")] -use bitwarden_core::{ - platform::client_platform::ClientPlatform, tool::ClientExporters, tool::ClientSends, - vault::ClientVault, -}; - -#[cfg(feature = "internal")] -use bitwarden_generators::{ClientGenerator, ClientGeneratorExt}; -use uuid::Uuid; - -pub struct Client(bitwarden_core::Client); - -impl Client { - pub fn new(settings: Option) -> Self { - Self(bitwarden_core::Client::new(settings)) - } - - #[cfg(feature = "internal")] - pub fn load_flags(&mut self, flags: std::collections::HashMap) { - self.0.load_flags(flags) - } - - pub fn get_access_token_organization(&self) -> Option { - self.0.get_access_token_organization() - } - - #[cfg(feature = "internal")] - pub fn kdf(&self) -> ClientKdf { - self.0.kdf() - } - - pub fn auth(&mut self) -> ClientAuth { - self.0.auth() - } - - #[cfg(feature = "internal")] - pub fn vault(&mut self) -> ClientVault { - self.0.vault() - } - - #[cfg(feature = "internal")] - pub fn platform(&mut self) -> ClientPlatform { - self.0.platform() - } - - #[cfg(feature = "internal")] - pub fn sends(&mut self) -> ClientSends { - self.0.sends() - } - - #[cfg(feature = "internal")] - pub fn generator(&self) -> ClientGenerator { - self.0.generator() - } - - #[cfg(feature = "internal")] - pub fn exporters(&self) -> ClientExporters { - self.0.exporters() - } - - #[cfg(feature = "internal")] - pub fn crypto(&mut self) -> ClientCrypto { - self.0.crypto() - } - - #[cfg(feature = "secrets")] - pub fn secrets(&mut self) -> ClientSecrets { - self.0.secrets() - } - - #[cfg(feature = "secrets")] - pub fn projects(&mut self) -> ClientProjects { - self.0.projects() - } -} diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index b51fa1f74..5ea3666e8 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -1,23 +1,19 @@ -#[allow(hidden_glob_reexports)] -mod client; -pub use client::Client; - -pub use bitwarden_core::client::client_settings::ClientSettings; pub use bitwarden_core::*; #[cfg(feature = "internal")] -pub mod generators { - pub use bitwarden_generators::{ - PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, - }; +pub mod internal { + pub mod generators { + pub use bitwarden_generators::*; + } + + pub mod send { + pub use bitwarden_send::*; + } } +#[cfg(feature = "internal")] +pub use internal::*; #[cfg(feature = "secrets")] pub mod secrets_manager { - pub mod projects { - pub use bitwarden_sm::projects::*; - } - pub mod secrets { - pub use bitwarden_sm::secrets::*; - } + pub use bitwarden_sm::*; } diff --git a/crates/bw/src/main.rs b/crates/bw/src/main.rs index f874423c6..4fb79d35b 100644 --- a/crates/bw/src/main.rs +++ b/crates/bw/src/main.rs @@ -1,6 +1,6 @@ use bitwarden::{ auth::RegisterRequest, - generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, + generators::{ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest}, ClientSettings, }; use bitwarden_cli::{install_color_eyre, text_prompt_when_none, Color}; diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 7b35b809d..4d2f5db18 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -11,6 +11,7 @@ use bitwarden::{ SecretCreateRequest, SecretGetRequest, SecretIdentifiersByProjectRequest, SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, }, + ClientProjectsExt, ClientSecretsExt, }, ClientSettings, }; From 15abebb01062e564ed3ad480c3799f9ead06ea03 Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 6 Jun 2024 10:39:46 +0200 Subject: [PATCH 06/28] Refactor exporters to depend on core not the inverse --- Cargo.lock | 4 +- crates/bitwarden-core/Cargo.toml | 1 - crates/bitwarden-core/src/auth/client_auth.rs | 2 + crates/bitwarden-core/src/client/client.rs | 9 + crates/bitwarden-core/src/error.rs | 8 +- crates/bitwarden-core/src/lib.rs | 2 - .../src/tool/exporters/client_exporter.rs | 37 --- crates/bitwarden-core/src/tool/mod.rs | 2 - .../bitwarden-core/src/vault/cipher/field.rs | 8 +- crates/bitwarden-core/src/vault/cipher/mod.rs | 4 +- .../src/vault/cipher/secure_note.rs | 2 +- crates/bitwarden-exporters/Cargo.toml | 6 + .../src/client_exporter.rs | 48 ++++ crates/bitwarden-exporters/src/csv.rs | 4 +- .../bitwarden-exporters/src/encrypted_json.rs | 4 +- crates/bitwarden-exporters/src/error.rs | 16 ++ crates/bitwarden-exporters/src/export.rs | 48 ++++ crates/bitwarden-exporters/src/json.rs | 6 +- crates/bitwarden-exporters/src/lib.rs | 154 +---------- .../src/models.rs} | 254 +++++++++--------- crates/bitwarden-send/src/send.rs | 2 + crates/bitwarden-uniffi/src/docs.rs | 2 +- crates/bitwarden-uniffi/src/error.rs | 9 + crates/bitwarden-uniffi/src/tool/mod.rs | 2 +- crates/bitwarden/Cargo.toml | 1 + crates/bitwarden/src/lib.rs | 4 + crates/bitwarden/test.sqlite | Bin 0 -> 12288 bytes 27 files changed, 309 insertions(+), 330 deletions(-) delete mode 100644 crates/bitwarden-core/src/tool/exporters/client_exporter.rs delete mode 100644 crates/bitwarden-core/src/tool/mod.rs create mode 100644 crates/bitwarden-exporters/src/client_exporter.rs create mode 100644 crates/bitwarden-exporters/src/error.rs create mode 100644 crates/bitwarden-exporters/src/export.rs rename crates/{bitwarden-core/src/tool/exporters/mod.rs => bitwarden-exporters/src/models.rs} (55%) create mode 100644 crates/bitwarden/test.sqlite diff --git a/Cargo.lock b/Cargo.lock index 35db76950..84b4de82a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -439,7 +439,6 @@ dependencies = [ "bitwarden-api-api", "bitwarden-api-identity", "bitwarden-crypto", - "bitwarden-exporters", "chrono", "coset", "getrandom", @@ -504,12 +503,15 @@ name = "bitwarden-exporters" version = "0.5.0" dependencies = [ "base64 0.22.1", + "bitwarden-core", "bitwarden-crypto", "chrono", "csv", + "schemars", "serde", "serde_json", "thiserror", + "uniffi", "uuid", ] diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index a59e7a33e..2d5aadf10 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -36,7 +36,6 @@ base64 = ">=0.21.2, <0.23" bitwarden-api-api = { workspace = true } bitwarden-api-identity = { workspace = true } bitwarden-crypto = { workspace = true } -bitwarden-exporters = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", "serde", diff --git a/crates/bitwarden-core/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs index 88f8b0a09..1eb246ccf 100644 --- a/crates/bitwarden-core/src/auth/client_auth.rs +++ b/crates/bitwarden-core/src/auth/client_auth.rs @@ -171,6 +171,7 @@ impl<'a> Client { } } +/* #[cfg(test)] mod tests { @@ -269,3 +270,4 @@ mod tests { assert_eq!(res.value, "TEST"); } } + */ diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index 5872996fa..aba4ebab3 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -276,6 +276,15 @@ impl Client { enc.set_org_keys(org_keys)?; Ok(&*enc) } + + pub fn get_kdf(&self) -> Result { + match &self.login_method { + Some(LoginMethod::User( + UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, + )) => Ok(kdf.clone()), + _ => Err(Error::NotAuthenticated), + } + } } #[cfg(test)] diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index 5f0b0f7d9..0525d98ea 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -4,8 +4,6 @@ use std::{borrow::Cow, fmt::Debug}; use bitwarden_api_api::apis::Error as ApiError; use bitwarden_api_identity::apis::Error as IdentityError; -#[cfg(feature = "internal")] -use bitwarden_exporters::ExportError; #[cfg(feature = "uniffi")] use passkey::client::WebauthnError; use reqwest::StatusCode; @@ -53,10 +51,6 @@ pub enum Error { #[error("The state file could not be read")] InvalidStateFile, - #[cfg(feature = "internal")] - #[error(transparent)] - ExportError(#[from] ExportError), - #[cfg(feature = "uniffi")] #[error("Webauthn error: {0:?}")] WebauthnError(WebauthnError), @@ -150,7 +144,7 @@ macro_rules! require { ($val:expr) => { match $val { Some(val) => val, - None => return Err($crate::error::Error::MissingFields(stringify!($val))), + None => return Err($crate::error::Error::MissingFields(stringify!($val)).into()), } }; } diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index e892e3935..6429d0a0f 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -70,8 +70,6 @@ pub mod mobile; pub mod platform; #[cfg(feature = "secrets")] pub mod secrets_manager; -#[cfg(feature = "internal")] -pub mod tool; #[cfg(feature = "uniffi")] pub(crate) mod uniffi_support; mod util; diff --git a/crates/bitwarden-core/src/tool/exporters/client_exporter.rs b/crates/bitwarden-core/src/tool/exporters/client_exporter.rs deleted file mode 100644 index 7efbc7fa3..000000000 --- a/crates/bitwarden-core/src/tool/exporters/client_exporter.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::{ - error::Result, - tool::exporters::{export_organization_vault, export_vault, ExportFormat}, - vault::{Cipher, Collection, Folder}, - Client, -}; - -pub struct ClientExporters<'a> { - client: &'a crate::Client, -} - -impl<'a> ClientExporters<'a> { - /// **Draft:** Export the vault as a CSV, JSON, or encrypted JSON file. - pub async fn export_vault( - &self, - folders: Vec, - ciphers: Vec, - format: ExportFormat, - ) -> Result { - export_vault(self.client, folders, ciphers, format) - } - - pub async fn export_organization_vault( - &self, - collections: Vec, - ciphers: Vec, - format: ExportFormat, - ) -> Result { - export_organization_vault(collections, ciphers, format) - } -} - -impl<'a> Client { - pub fn exporters(&'a self) -> ClientExporters<'a> { - ClientExporters { client: self } - } -} diff --git a/crates/bitwarden-core/src/tool/mod.rs b/crates/bitwarden-core/src/tool/mod.rs deleted file mode 100644 index 8034151d7..000000000 --- a/crates/bitwarden-core/src/tool/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod exporters; -pub use exporters::{ClientExporters, ExportFormat}; diff --git a/crates/bitwarden-core/src/vault/cipher/field.rs b/crates/bitwarden-core/src/vault/cipher/field.rs index 8a7b1d5f5..aaeee196c 100644 --- a/crates/bitwarden-core/src/vault/cipher/field.rs +++ b/crates/bitwarden-core/src/vault/cipher/field.rs @@ -34,11 +34,11 @@ pub struct Field { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] pub struct FieldView { - pub(crate) name: Option, - pub(crate) value: Option, - pub(crate) r#type: FieldType, + pub name: Option, + pub value: Option, + pub r#type: FieldType, - pub(crate) linked_id: Option, + pub linked_id: Option, } impl KeyEncryptable for FieldView { diff --git a/crates/bitwarden-core/src/vault/cipher/mod.rs b/crates/bitwarden-core/src/vault/cipher/mod.rs index 91e5bc7eb..f6adaa601 100644 --- a/crates/bitwarden-core/src/vault/cipher/mod.rs +++ b/crates/bitwarden-core/src/vault/cipher/mod.rs @@ -16,5 +16,7 @@ pub use cipher::{Cipher, CipherListView, CipherRepromptType, CipherType, CipherV pub use field::FieldView; #[cfg(feature = "uniffi")] pub(crate) use login::Fido2CredentialFullView; -pub use login::{Fido2Credential, Fido2CredentialNewView, Fido2CredentialView}; +pub use login::{ + Fido2Credential, Fido2CredentialNewView, Fido2CredentialView, LoginUriView, LoginView, +}; pub use secure_note::SecureNoteType; diff --git a/crates/bitwarden-core/src/vault/cipher/secure_note.rs b/crates/bitwarden-core/src/vault/cipher/secure_note.rs index be4fc6689..af4ab4cd7 100644 --- a/crates/bitwarden-core/src/vault/cipher/secure_note.rs +++ b/crates/bitwarden-core/src/vault/cipher/secure_note.rs @@ -24,7 +24,7 @@ pub struct SecureNote { #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] pub struct SecureNoteView { - pub(crate) r#type: SecureNoteType, + pub r#type: SecureNoteType, } impl KeyEncryptable for SecureNoteView { diff --git a/crates/bitwarden-exporters/Cargo.toml b/crates/bitwarden-exporters/Cargo.toml index 053bee22f..1ce18db40 100644 --- a/crates/bitwarden-exporters/Cargo.toml +++ b/crates/bitwarden-exporters/Cargo.toml @@ -14,8 +14,12 @@ repository.workspace = true license-file.workspace = true keywords.workspace = true +[features] +uniffi = ["dep:uniffi"] # Uniffi bindings + [dependencies] base64 = ">=0.22.1, <0.23" +bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", @@ -23,9 +27,11 @@ chrono = { version = ">=0.4.26, <0.5", features = [ "std", ], default-features = false } csv = "1.3.0" +schemars = { version = ">=0.8.9, <0.9", features = ["uuid1", "chrono"] } serde = { version = ">=1.0, <2.0", features = ["derive"] } serde_json = ">=1.0.96, <2.0" thiserror = ">=1.0.40, <2.0" +uniffi = { version = "=0.27.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde", "v4"] } [dev-dependencies] diff --git a/crates/bitwarden-exporters/src/client_exporter.rs b/crates/bitwarden-exporters/src/client_exporter.rs new file mode 100644 index 000000000..0b4a3dab5 --- /dev/null +++ b/crates/bitwarden-exporters/src/client_exporter.rs @@ -0,0 +1,48 @@ +use bitwarden_core::{ + error::Result, + vault::{Cipher, Collection, Folder}, + Client, +}; + +use crate::{ + export::{export_organization_vault, export_vault}, + ExportError, ExportFormat, +}; + +pub struct ClientExporters<'a> { + client: &'a Client, +} + +impl<'a> ClientExporters<'a> { + fn new(client: &'a Client) -> Self { + Self { client } + } + + pub async fn export_vault( + &self, + folders: Vec, + ciphers: Vec, + format: ExportFormat, + ) -> Result { + export_vault(&self.client, folders, ciphers, format) + } + + pub async fn export_organization_vault( + &self, + collections: Vec, + ciphers: Vec, + format: ExportFormat, + ) -> Result { + export_organization_vault(collections, ciphers, format) + } +} + +pub trait ClientExportersExt<'a> { + fn exporters(&'a self) -> ClientExporters<'a>; +} + +impl<'a> ClientExportersExt<'a> for Client { + fn exporters(&'a self) -> ClientExporters<'a> { + ClientExporters::new(self) + } +} diff --git a/crates/bitwarden-exporters/src/csv.rs b/crates/bitwarden-exporters/src/csv.rs index a0dcd1040..30c56f74a 100644 --- a/crates/bitwarden-exporters/src/csv.rs +++ b/crates/bitwarden-exporters/src/csv.rs @@ -5,7 +5,7 @@ use serde::Serializer; use thiserror::Error; use uuid::Uuid; -use crate::{Cipher, CipherType, Field, Folder}; +use crate::models::{Cipher, CipherType, Field, Folder}; #[derive(Debug, Error)] pub enum CsvError { @@ -111,7 +111,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::{Card, Identity, Login, LoginUri}; + use crate::models::{Card, Identity, Login, LoginUri}; #[test] fn test_export_csv() { diff --git a/crates/bitwarden-exporters/src/encrypted_json.rs b/crates/bitwarden-exporters/src/encrypted_json.rs index 0378bd9f3..a4b4901c1 100644 --- a/crates/bitwarden-exporters/src/encrypted_json.rs +++ b/crates/bitwarden-exporters/src/encrypted_json.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use crate::{ json::{self, export_json}, - Cipher, Folder, + models::{Cipher, Folder}, }; #[derive(Error, Debug)] @@ -84,7 +84,7 @@ mod tests { use std::num::NonZeroU32; use super::*; - use crate::{ + use crate::models::{ Card, Cipher, CipherType, Field, Identity, Login, LoginUri, SecureNote, SecureNoteType, }; diff --git a/crates/bitwarden-exporters/src/error.rs b/crates/bitwarden-exporters/src/error.rs new file mode 100644 index 000000000..ea9d17ee7 --- /dev/null +++ b/crates/bitwarden-exporters/src/error.rs @@ -0,0 +1,16 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ExportError { + #[error("CSV error: {0}")] + Csv(#[from] crate::csv::CsvError), + #[error("JSON error: {0}")] + Json(#[from] crate::json::JsonError), + #[error("Encrypted JSON error: {0}")] + EncryptedJsonError(#[from] crate::encrypted_json::EncryptedJsonError), + + #[error(transparent)] + BitwardenError(#[from] bitwarden_core::error::Error), + #[error(transparent)] + BitwardenCryptoError(#[from] bitwarden_crypto::CryptoError), +} diff --git a/crates/bitwarden-exporters/src/export.rs b/crates/bitwarden-exporters/src/export.rs new file mode 100644 index 000000000..cd7dd4898 --- /dev/null +++ b/crates/bitwarden-exporters/src/export.rs @@ -0,0 +1,48 @@ +use bitwarden_core::{ + error::Error, + vault::{Cipher, CipherView, Collection, Folder, FolderView}, + Client, +}; +use bitwarden_crypto::KeyDecryptable; + +use crate::{ + csv::export_csv, encrypted_json::export_encrypted_json, json::export_json, ExportError, + ExportFormat, +}; + +pub(crate) fn export_vault( + client: &Client, + folders: Vec, + ciphers: Vec, + format: ExportFormat, +) -> Result { + let enc = client.get_encryption_settings()?; + let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; + + let folders: Vec = folders.decrypt_with_key(key)?; + let folders: Vec = + folders.into_iter().flat_map(|f| f.try_into()).collect(); + + let ciphers: Vec = ciphers.decrypt_with_key(key)?; + let ciphers: Vec = + ciphers.into_iter().flat_map(|c| c.try_into()).collect(); + + match format { + ExportFormat::Csv => Ok(export_csv(folders, ciphers)?), + ExportFormat::Json => Ok(export_json(folders, ciphers)?), + ExportFormat::EncryptedJson { password } => Ok(export_encrypted_json( + folders, + ciphers, + password, + client.get_kdf()?, + )?), + } +} + +pub(crate) fn export_organization_vault( + _collections: Vec, + _ciphers: Vec, + _format: ExportFormat, +) -> Result { + todo!(); +} diff --git a/crates/bitwarden-exporters/src/json.rs b/crates/bitwarden-exporters/src/json.rs index 3f6c72c1f..71e7a374d 100644 --- a/crates/bitwarden-exporters/src/json.rs +++ b/crates/bitwarden-exporters/src/json.rs @@ -2,7 +2,9 @@ use chrono::{DateTime, Utc}; use thiserror::Error; use uuid::Uuid; -use crate::{Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote}; +use crate::models::{ + Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote, +}; #[derive(Error, Debug)] pub enum JsonError { @@ -270,7 +272,7 @@ mod tests { use std::{fs, io::Read, path::PathBuf}; use super::*; - use crate::{Cipher, Field, LoginUri, SecureNoteType}; + use crate::models::{Cipher, Field, LoginUri, SecureNoteType}; #[test] fn test_convert_login() { diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index 762556388..c4a125a55 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -1,152 +1,24 @@ -use std::fmt; - -use bitwarden_crypto::Kdf; -use chrono::{DateTime, Utc}; -use thiserror::Error; -use uuid::Uuid; +use schemars::JsonSchema; mod csv; use crate::csv::export_csv; mod json; use json::export_json; +mod client_exporter; +pub use client_exporter::{ClientExporters, ClientExportersExt}; mod encrypted_json; +mod error; +pub(crate) mod export; +pub use error::ExportError; +mod models; -use encrypted_json::export_encrypted_json; +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!(); -pub enum Format { +#[derive(JsonSchema)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] +pub enum ExportFormat { Csv, Json, - EncryptedJson { password: String, kdf: Kdf }, -} - -/// Export representation of a Bitwarden folder. -/// -/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API -/// that is not tied to the internal vault models. We may revisit this in the future. -pub struct Folder { - pub id: Uuid, - pub name: String, -} - -/// Export representation of a Bitwarden cipher. -/// -/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API -/// that is not tied to the internal vault models. We may revisit this in the future. -pub struct Cipher { - pub id: Uuid, - pub folder_id: Option, - - pub name: String, - pub notes: Option, - - pub r#type: CipherType, - - pub favorite: bool, - pub reprompt: u8, - - pub fields: Vec, - - pub revision_date: DateTime, - pub creation_date: DateTime, - pub deleted_date: Option>, -} - -#[derive(Clone)] -pub struct Field { - pub name: Option, - pub value: Option, - pub r#type: u8, - pub linked_id: Option, -} - -pub enum CipherType { - Login(Box), - SecureNote(Box), - Card(Box), - Identity(Box), -} - -impl fmt::Display for CipherType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - CipherType::Login(_) => write!(f, "login"), - CipherType::SecureNote(_) => write!(f, "note"), - CipherType::Card(_) => write!(f, "card"), - CipherType::Identity(_) => write!(f, "identity"), - } - } -} - -pub struct Login { - pub username: Option, - pub password: Option, - pub login_uris: Vec, - pub totp: Option, -} - -pub struct LoginUri { - pub uri: Option, - pub r#match: Option, -} - -pub struct Card { - pub cardholder_name: Option, - pub exp_month: Option, - pub exp_year: Option, - pub code: Option, - pub brand: Option, - pub number: Option, -} - -pub struct SecureNote { - pub r#type: SecureNoteType, -} - -pub enum SecureNoteType { - Generic = 0, -} - -pub struct Identity { - pub title: Option, - pub first_name: Option, - pub middle_name: Option, - pub last_name: Option, - pub address1: Option, - pub address2: Option, - pub address3: Option, - pub city: Option, - pub state: Option, - pub postal_code: Option, - pub country: Option, - pub company: Option, - pub email: Option, - pub phone: Option, - pub ssn: Option, - pub username: Option, - pub passport_number: Option, - pub license_number: Option, -} - -#[derive(Error, Debug)] -pub enum ExportError { - #[error("CSV error: {0}")] - Csv(#[from] csv::CsvError), - #[error("JSON error: {0}")] - Json(#[from] json::JsonError), - #[error("Encrypted JSON error: {0}")] - EncryptedJsonError(#[from] encrypted_json::EncryptedJsonError), -} - -pub fn export( - folders: Vec, - ciphers: Vec, - format: Format, -) -> Result { - match format { - Format::Csv => Ok(export_csv(folders, ciphers)?), - Format::Json => Ok(export_json(folders, ciphers)?), - Format::EncryptedJson { password, kdf } => { - Ok(export_encrypted_json(folders, ciphers, password, kdf)?) - } - } + EncryptedJson { password: String }, } diff --git a/crates/bitwarden-core/src/tool/exporters/mod.rs b/crates/bitwarden-exporters/src/models.rs similarity index 55% rename from crates/bitwarden-core/src/tool/exporters/mod.rs rename to crates/bitwarden-exporters/src/models.rs index 359cab8c5..614be9f5e 100644 --- a/crates/bitwarden-core/src/tool/exporters/mod.rs +++ b/crates/bitwarden-exporters/src/models.rs @@ -1,86 +1,124 @@ -use bitwarden_crypto::KeyDecryptable; -use bitwarden_exporters::export; -use schemars::JsonSchema; - -use crate::{ - client::{LoginMethod, UserLoginMethod}, - error::{require, Error, Result}, - vault::{ - login::LoginUriView, Cipher, CipherType, CipherView, Collection, FieldView, Folder, - FolderView, SecureNoteType, - }, - Client, +use std::fmt; + +use bitwarden_core::{ + require, + vault::{CipherView, FieldView, FolderView, LoginUriView}, }; +use chrono::{DateTime, Utc}; +use uuid::Uuid; + +use crate::ExportError; + +/// Export representation of a Bitwarden folder. +/// +/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API +/// that is not tied to the internal vault models. We may revisit this in the future. +pub(crate) struct Folder { + pub id: Uuid, + pub name: String, +} + +/// Export representation of a Bitwarden cipher. +/// +/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API +/// that is not tied to the internal vault models. We may revisit this in the future. +pub(crate) struct Cipher { + pub id: Uuid, + pub folder_id: Option, + + pub name: String, + pub notes: Option, + + pub r#type: CipherType, + + pub favorite: bool, + pub reprompt: u8, -mod client_exporter; -pub use client_exporter::ClientExporters; + pub fields: Vec, -#[derive(JsonSchema)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] -pub enum ExportFormat { - Csv, - Json, - EncryptedJson { password: String }, + pub revision_date: DateTime, + pub creation_date: DateTime, + pub deleted_date: Option>, } -pub(super) fn export_vault( - client: &Client, - folders: Vec, - ciphers: Vec, - format: ExportFormat, -) -> Result { - let enc = client.get_encryption_settings()?; - let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; +#[derive(Clone)] +pub(crate) struct Field { + pub name: Option, + pub value: Option, + pub r#type: u8, + pub linked_id: Option, +} + +pub(crate) enum CipherType { + Login(Box), + SecureNote(Box), + Card(Box), + Identity(Box), +} + +impl fmt::Display for CipherType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CipherType::Login(_) => write!(f, "login"), + CipherType::SecureNote(_) => write!(f, "note"), + CipherType::Card(_) => write!(f, "card"), + CipherType::Identity(_) => write!(f, "identity"), + } + } +} - let folders: Vec = folders.decrypt_with_key(key)?; - let folders: Vec = - folders.into_iter().flat_map(|f| f.try_into()).collect(); +pub(crate) struct Login { + pub username: Option, + pub password: Option, + pub login_uris: Vec, + pub totp: Option, +} - let ciphers: Vec = ciphers.decrypt_with_key(key)?; - let ciphers: Vec = - ciphers.into_iter().flat_map(|c| c.try_into()).collect(); +pub(crate) struct LoginUri { + pub uri: Option, + pub r#match: Option, +} - let format = convert_format(client, format)?; +pub(crate) struct Card { + pub cardholder_name: Option, + pub exp_month: Option, + pub exp_year: Option, + pub code: Option, + pub brand: Option, + pub number: Option, +} - Ok(export(folders, ciphers, format)?) +pub(crate) struct SecureNote { + pub r#type: SecureNoteType, } -fn convert_format( - client: &Client, - format: ExportFormat, -) -> Result { - let login_method = client - .login_method - .as_ref() - .ok_or(Error::NotAuthenticated)?; - - let kdf = match login_method { - LoginMethod::User( - UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, - ) => kdf, - _ => return Err(Error::NotAuthenticated), - }; - - Ok(match format { - ExportFormat::Csv => bitwarden_exporters::Format::Csv, - ExportFormat::Json => bitwarden_exporters::Format::Json, - ExportFormat::EncryptedJson { password } => bitwarden_exporters::Format::EncryptedJson { - password, - kdf: kdf.clone(), - }, - }) +pub(crate) enum SecureNoteType { + Generic = 0, } -pub(super) fn export_organization_vault( - _collections: Vec, - _ciphers: Vec, - _format: ExportFormat, -) -> Result { - todo!(); +pub(crate) struct Identity { + pub title: Option, + pub first_name: Option, + pub middle_name: Option, + pub last_name: Option, + pub address1: Option, + pub address2: Option, + pub address3: Option, + pub city: Option, + pub state: Option, + pub postal_code: Option, + pub country: Option, + pub company: Option, + pub email: Option, + pub phone: Option, + pub ssn: Option, + pub username: Option, + pub passport_number: Option, + pub license_number: Option, } -impl TryFrom for bitwarden_exporters::Folder { - type Error = Error; +impl TryFrom for Folder { + type Error = ExportError; fn try_from(value: FolderView) -> Result { Ok(Self { @@ -90,14 +128,14 @@ impl TryFrom for bitwarden_exporters::Folder { } } -impl TryFrom for bitwarden_exporters::Cipher { - type Error = Error; +impl TryFrom for Cipher { + type Error = ExportError; fn try_from(value: CipherView) -> Result { let r = match value.r#type { - CipherType::Login => { + bitwarden_core::vault::CipherType::Login => { let l = require!(value.login); - bitwarden_exporters::CipherType::Login(Box::new(bitwarden_exporters::Login { + CipherType::Login(Box::new(Login { username: l.username, password: l.password, login_uris: l @@ -109,18 +147,18 @@ impl TryFrom for bitwarden_exporters::Cipher { totp: l.totp, })) } - CipherType::SecureNote => bitwarden_exporters::CipherType::SecureNote(Box::new( - bitwarden_exporters::SecureNote { + bitwarden_core::vault::CipherType::SecureNote => { + CipherType::SecureNote(Box::new(SecureNote { r#type: value .secure_note .map(|t| t.r#type) - .unwrap_or(SecureNoteType::Generic) + .unwrap_or(bitwarden_core::vault::SecureNoteType::Generic) .into(), - }, - )), - CipherType::Card => { + })) + } + bitwarden_core::vault::CipherType::Card => { let c = require!(value.card); - bitwarden_exporters::CipherType::Card(Box::new(bitwarden_exporters::Card { + CipherType::Card(Box::new(Card { cardholder_name: c.cardholder_name, exp_month: c.exp_month, exp_year: c.exp_year, @@ -129,9 +167,9 @@ impl TryFrom for bitwarden_exporters::Cipher { number: c.number, })) } - CipherType::Identity => { + bitwarden_core::vault::CipherType::Identity => { let i = require!(value.identity); - bitwarden_exporters::CipherType::Identity(Box::new(bitwarden_exporters::Identity { + CipherType::Identity(Box::new(Identity { title: i.title, first_name: i.first_name, middle_name: i.middle_name, @@ -175,7 +213,7 @@ impl TryFrom for bitwarden_exporters::Cipher { } } -impl From for bitwarden_exporters::Field { +impl From for Field { fn from(value: FieldView) -> Self { Self { name: value.name, @@ -186,7 +224,7 @@ impl From for bitwarden_exporters::Field { } } -impl From for bitwarden_exporters::LoginUri { +impl From for LoginUri { fn from(value: LoginUriView) -> Self { Self { r#match: value.r#match.map(|v| v as u8), @@ -195,23 +233,20 @@ impl From for bitwarden_exporters::LoginUri { } } -impl From for bitwarden_exporters::SecureNoteType { - fn from(value: SecureNoteType) -> Self { +impl From for SecureNoteType { + fn from(value: bitwarden_core::vault::SecureNoteType) -> Self { match value { - SecureNoteType::Generic => bitwarden_exporters::SecureNoteType::Generic, + bitwarden_core::vault::SecureNoteType::Generic => SecureNoteType::Generic, } } } #[cfg(test)] mod tests { - use std::num::NonZeroU32; - - use bitwarden_crypto::Kdf; use chrono::{DateTime, Utc}; use super::*; - use crate::vault::{login::LoginView, CipherRepromptType}; + use bitwarden_core::vault::{CipherRepromptType, LoginView}; #[test] fn test_try_from_folder_view() { @@ -221,7 +256,7 @@ mod tests { revision_date: "2024-01-30T17:55:36.150Z".parse().unwrap(), }; - let f: bitwarden_exporters::Folder = view.try_into().unwrap(); + let f: Folder = view.try_into().unwrap(); assert_eq!( f.id, @@ -233,7 +268,7 @@ mod tests { #[test] fn test_try_from_cipher_view_login() { let cipher_view = CipherView { - r#type: CipherType::Login, + r#type: bitwarden_core::vault::CipherType::Login, login: Some(LoginView { username: Some("test_username".to_string()), password: Some("test_password".to_string()), @@ -267,7 +302,7 @@ mod tests { revision_date: "2024-01-30T17:55:36.150Z".parse().unwrap(), }; - let cipher: bitwarden_exporters::Cipher = cipher_view.try_into().unwrap(); + let cipher: Cipher = cipher_view.try_into().unwrap(); assert_eq!( cipher.id, @@ -289,7 +324,7 @@ mod tests { ); assert_eq!(cipher.deleted_date, None); - if let bitwarden_exporters::CipherType::Login(l) = cipher.r#type { + if let CipherType::Login(l) = cipher.r#type { assert_eq!(l.username, Some("test_username".to_string())); assert_eq!(l.password, Some("test_password".to_string())); assert!(l.login_uris.is_empty()); @@ -298,35 +333,4 @@ mod tests { panic!("Expected login type"); } } - - #[test] - fn test_convert_format() { - let mut 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(), - kdf: Kdf::PBKDF2 { - iterations: NonZeroU32::new(600_000).unwrap(), - }, - })); - - assert!(matches!( - convert_format(&client, ExportFormat::Csv).unwrap(), - bitwarden_exporters::Format::Csv - )); - assert!(matches!( - convert_format(&client, ExportFormat::Json).unwrap(), - bitwarden_exporters::Format::Json - )); - assert!(matches!( - convert_format( - &client, - ExportFormat::EncryptedJson { - password: "password".to_string() - } - ) - .unwrap(), - bitwarden_exporters::Format::EncryptedJson { .. } - )); - } } diff --git a/crates/bitwarden-send/src/send.rs b/crates/bitwarden-send/src/send.rs index 2a7cb2ac3..e53474821 100644 --- a/crates/bitwarden-send/src/send.rs +++ b/crates/bitwarden-send/src/send.rs @@ -360,6 +360,7 @@ impl TryFrom for SendText { } } +/* #[cfg(test)] mod tests { use bitwarden_core::client::{encryption_settings::EncryptionSettings, Kdf}; @@ -588,3 +589,4 @@ mod tests { assert!(v.has_password); } } +*/ diff --git a/crates/bitwarden-uniffi/src/docs.rs b/crates/bitwarden-uniffi/src/docs.rs index 3d8cc95ee..5edbc7144 100644 --- a/crates/bitwarden-uniffi/src/docs.rs +++ b/crates/bitwarden-uniffi/src/docs.rs @@ -1,10 +1,10 @@ use bitwarden::{ auth::password::MasterPasswordPolicyOptions, + exporters::ExportFormat, generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest}, platform::FingerprintRequest, send::{Send, SendListView, SendView}, - tool::ExportFormat, vault::{Cipher, CipherView, Collection, Folder, FolderView, TotpResponse}, }; use bitwarden_crypto::{HashPurpose, Kdf}; diff --git a/crates/bitwarden-uniffi/src/error.rs b/crates/bitwarden-uniffi/src/error.rs index 5eef9bbd5..37a84b0e6 100644 --- a/crates/bitwarden-uniffi/src/error.rs +++ b/crates/bitwarden-uniffi/src/error.rs @@ -6,6 +6,7 @@ use std::fmt::{Display, Formatter}; #[uniffi(flat_error)] pub enum BitwardenError { E(bitwarden::error::Error), + Ee(bitwarden::exporters::ExportError), } impl From for BitwardenError { @@ -14,10 +15,17 @@ impl From for BitwardenError { } } +impl From for BitwardenError { + fn from(e: bitwarden::exporters::ExportError) -> Self { + Self::Ee(e) + } +} + impl Display for BitwardenError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::E(e) => Display::fmt(e, f), + Self::Ee(e) => Display::fmt(e, f), } } } @@ -26,6 +34,7 @@ impl std::error::Error for BitwardenError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { BitwardenError::E(e) => Some(e), + BitwardenError::Ee(e) => Some(e), } } } diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index ef2387e77..22adfc6a6 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -2,11 +2,11 @@ use std::sync::Arc; use bitwarden::{ error::Error, + exporters::{ClientExportersExt, ExportFormat}, generators::{ ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, }, - tool::ExportFormat, vault::{Cipher, Collection, Folder}, }; diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 2e87a7a3f..dd94af08c 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -28,6 +28,7 @@ no-memory-hardening = [ uniffi = [ "bitwarden-core/uniffi", "bitwarden-crypto/uniffi", + "bitwarden-exporters/uniffi", "bitwarden-generators/uniffi", "bitwarden-send/uniffi", ] # Uniffi bindings diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index 5ea3666e8..548e2acf8 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -6,6 +6,10 @@ pub mod internal { pub use bitwarden_generators::*; } + pub mod exporters { + pub use bitwarden_exporters::*; + } + pub mod send { pub use bitwarden_send::*; } diff --git a/crates/bitwarden/test.sqlite b/crates/bitwarden/test.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..741c5fdc34b49bffd36fb78d5ded23b3113e44e1 GIT binary patch literal 12288 zcmeI$&raJg7y$4D(EcEyPU3(xE>TXKNFYg@0+o;`qZ-f>C<}*F?EyRIBnV3 zVG@Tuz#d@_Flo2lcHEAWrfKi62iS2g{lnOSUAO78VkM40`?G)P#oaBJ2**k-WKG1C zv~*9BWocPaBuSbSbyUmT>=*y z@|gDO?8_nk`T;G!dHw0_XZhmW{pTw2)tu_vwx6~AdEGO!rk*iSMqkW$NUs{cWta;Y zf6+v$riQGJ0`d%T5(evHT#!(zskM;$m|eBKkcyLRFD6!VPY*SOr+JM8{e}**@^N?L_fZ@xpBj&nP zHmrd=hE3((>9(69UoK7vEK{q88O@ Date: Fri, 7 Jun 2024 18:11:15 +0200 Subject: [PATCH 07/28] Move client methods to InternalClient --- .../bitwarden-core/src/auth/auth_request.rs | 6 +- crates/bitwarden-core/src/auth/client_auth.rs | 2 +- .../src/auth/login/access_token.rs | 46 ++-- .../bitwarden-core/src/auth/login/api_key.rs | 22 +- .../src/auth/login/auth_request.rs | 18 +- crates/bitwarden-core/src/auth/login/mod.rs | 2 +- .../bitwarden-core/src/auth/login/password.rs | 20 +- .../src/auth/login/two_factor.rs | 2 +- .../src/auth/password/validate.rs | 45 ++-- crates/bitwarden-core/src/auth/register.rs | 2 +- crates/bitwarden-core/src/auth/renew.rs | 32 ++- crates/bitwarden-core/src/auth/tde.rs | 20 +- crates/bitwarden-core/src/client/client.rs | 233 ++---------------- crates/bitwarden-core/src/client/internal.rs | 183 ++++++++++++++ .../bitwarden-core/src/client/login_method.rs | 41 +++ crates/bitwarden-core/src/client/mod.rs | 4 + crates/bitwarden-core/src/mobile/crypto.rs | 57 +++-- .../src/mobile/vault/client_attachments.rs | 4 +- .../src/mobile/vault/client_ciphers.rs | 16 +- .../src/mobile/vault/client_collection.rs | 4 +- .../src/mobile/vault/client_folders.rs | 6 +- .../mobile/vault/client_password_history.rs | 4 +- .../src/platform/fido2/authenticator.rs | 18 +- .../src/platform/generate_fingerprint.rs | 3 +- .../src/platform/get_user_api_key.rs | 5 +- crates/bitwarden-core/src/vault/sync.rs | 4 +- crates/bitwarden-exporters/src/export.rs | 4 +- .../src/client_generator.rs | 2 +- crates/bitwarden-send/src/client_sends.rs | 9 +- crates/bitwarden-sm/src/projects/create.rs | 5 +- crates/bitwarden-sm/src/projects/delete.rs | 2 +- crates/bitwarden-sm/src/projects/get.rs | 4 +- crates/bitwarden-sm/src/projects/list.rs | 4 +- crates/bitwarden-sm/src/projects/update.rs | 5 +- crates/bitwarden-sm/src/secrets/create.rs | 5 +- crates/bitwarden-sm/src/secrets/delete.rs | 2 +- crates/bitwarden-sm/src/secrets/get.rs | 4 +- crates/bitwarden-sm/src/secrets/get_by_ids.rs | 4 +- crates/bitwarden-sm/src/secrets/list.rs | 8 +- crates/bitwarden-sm/src/secrets/sync.rs | 4 +- crates/bitwarden-sm/src/secrets/update.rs | 5 +- crates/bitwarden-uniffi/src/platform/mod.rs | 2 +- crates/bws/src/main.rs | 2 +- 43 files changed, 501 insertions(+), 369 deletions(-) create mode 100644 crates/bitwarden-core/src/client/internal.rs create mode 100644 crates/bitwarden-core/src/client/login_method.rs diff --git a/crates/bitwarden-core/src/auth/auth_request.rs b/crates/bitwarden-core/src/auth/auth_request.rs index 6f0b8fa2c..24a23680b 100644 --- a/crates/bitwarden-core/src/auth/auth_request.rs +++ b/crates/bitwarden-core/src/auth/auth_request.rs @@ -80,7 +80,7 @@ pub(crate) fn approve_auth_request( ) -> Result { let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(public_key)?)?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; Ok(AsymmetricEncString::encrypt_rsa2048_oaep_sha1( @@ -135,6 +135,7 @@ mod tests { let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap(); 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=".parse().unwrap(); client + .internal .initialize_user_crypto_master_key(master_key, user_key, private_key) .unwrap(); @@ -203,6 +204,7 @@ mod tests { .unwrap(); existing_device + .internal .initialize_user_crypto_master_key(master_key, user_key, private_key.parse().unwrap()) .unwrap(); @@ -234,12 +236,14 @@ mod tests { // same assert_eq!( existing_device + .internal .get_encryption_settings() .unwrap() .get_key(&None) .unwrap() .to_base64(), new_device + .internal .get_encryption_settings() .unwrap() .get_key(&None) diff --git a/crates/bitwarden-core/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs index 1eb246ccf..220bdc1aa 100644 --- a/crates/bitwarden-core/src/auth/client_auth.rs +++ b/crates/bitwarden-core/src/auth/client_auth.rs @@ -158,7 +158,7 @@ impl<'a> ClientAuth<'a> { #[cfg(feature = "internal")] fn trust_device(client: &Client) -> Result { - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let user_key = enc.get_key(&None).ok_or(Error::VaultLocked)?; diff --git a/crates/bitwarden-core/src/auth/login/access_token.rs b/crates/bitwarden-core/src/auth/login/access_token.rs index 9366e631f..d88f0d6b5 100644 --- a/crates/bitwarden-core/src/auth/login/access_token.rs +++ b/crates/bitwarden-core/src/auth/login/access_token.rs @@ -30,13 +30,15 @@ pub(crate) async fn login_access_token( if let Some(state_file) = &input.state_file { if let Ok(organization_id) = load_tokens_from_state(client, state_file, &access_token) { - client.set_login_method(LoginMethod::ServiceAccount( - ServiceAccountLoginMethod::AccessToken { - access_token, - organization_id, - state_file: Some(state_file.to_path_buf()), - }, - )); + client + .internal + .set_login_method(LoginMethod::ServiceAccount( + ServiceAccountLoginMethod::AccessToken { + access_token, + organization_id, + state_file: Some(state_file.to_path_buf()), + }, + )); return Ok(AccessTokenLoginResponse { authenticated: true, @@ -78,20 +80,22 @@ pub(crate) async fn login_access_token( _ = state::set(state_file, &access_token, state); } - client.set_tokens( + client.internal.set_tokens( r.access_token.clone(), r.refresh_token.clone(), r.expires_in, ); - client.set_login_method(LoginMethod::ServiceAccount( - ServiceAccountLoginMethod::AccessToken { - access_token, - organization_id, - state_file: input.state_file.clone(), - }, - )); - - client.initialize_crypto_single_key(encryption_key); + client + .internal + .set_login_method(LoginMethod::ServiceAccount( + ServiceAccountLoginMethod::AccessToken { + access_token, + organization_id, + state_file: input.state_file.clone(), + }, + )); + + client.internal.initialize_crypto_single_key(encryption_key); } AccessTokenLoginResponse::process_response(response) @@ -101,7 +105,7 @@ async fn request_access_token( client: &mut Client, input: &AccessToken, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; AccessTokenRequest::new(input.access_token_id, &input.client_secret) .send(config) .await @@ -125,8 +129,10 @@ fn load_tokens_from_state( .map_err(|_| "Bad organization id.")?; let encryption_key = SymmetricCryptoKey::try_from(client_state.encryption_key)?; - client.set_tokens(client_state.token, None, time_till_expiration as u64); - client.initialize_crypto_single_key(encryption_key); + client + .internal + .set_tokens(client_state.token, None, time_till_expiration as u64); + client.internal.initialize_crypto_single_key(encryption_key); return Ok(organization_id); } diff --git a/crates/bitwarden-core/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs index 8b83e3a38..51c71b7e9 100644 --- a/crates/bitwarden-core/src/auth/login/api_key.rs +++ b/crates/bitwarden-core/src/auth/login/api_key.rs @@ -32,7 +32,7 @@ pub(crate) async fn login_api_key( let kdf = client.auth().prelogin(email.clone()).await?; - client.set_tokens( + client.internal.set_tokens( r.access_token.clone(), r.refresh_token.clone(), r.expires_in, @@ -40,17 +40,21 @@ pub(crate) async fn login_api_key( let master_key = MasterKey::derive(input.password.as_bytes(), email.as_bytes(), &kdf)?; - client.set_login_method(LoginMethod::User(UserLoginMethod::ApiKey { - client_id: input.client_id.to_owned(), - client_secret: input.client_secret.to_owned(), - email, - kdf, - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::ApiKey { + client_id: input.client_id.to_owned(), + client_secret: input.client_secret.to_owned(), + email, + kdf, + })); let user_key: EncString = require!(r.key.as_deref()).parse()?; let private_key: EncString = require!(r.private_key.as_deref()).parse()?; - client.initialize_user_crypto_master_key(master_key, user_key, private_key)?; + client + .internal + .initialize_user_crypto_master_key(master_key, user_key, private_key)?; } ApiKeyLoginResponse::process_response(response) @@ -60,7 +64,7 @@ async fn request_api_identity_tokens( client: &mut Client, input: &ApiKeyLoginRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; ApiTokenRequest::new(&input.client_id, &input.client_secret) .send(config) .await diff --git a/crates/bitwarden-core/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs index fb449e5d4..5e4c8ffc5 100644 --- a/crates/bitwarden-core/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -30,7 +30,7 @@ pub(crate) async fn send_new_auth_request( email: String, device_identifier: String, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let auth = new_auth_request(&email)?; @@ -58,7 +58,7 @@ pub(crate) async fn complete_auth_request( client: &mut Client, auth_req: NewAuthRequestResponse, ) -> Result<()> { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = auth_requests_id_response_get( &config.api, @@ -86,16 +86,18 @@ pub(crate) async fn complete_auth_request( if let IdentityTokenResponse::Authenticated(r) = response { let kdf = Kdf::default(); - client.set_tokens( + client.internal.set_tokens( r.access_token.clone(), r.refresh_token.clone(), r.expires_in, ); - client.set_login_method(LoginMethod::User(UserLoginMethod::Username { - client_id: "web".to_owned(), - email: auth_req.email.to_owned(), - kdf: kdf.clone(), - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::Username { + client_id: "web".to_owned(), + email: auth_req.email.to_owned(), + kdf: kdf.clone(), + })); let method = match res.master_password_hash { Some(_) => AuthRequestMethod::MasterKey { diff --git a/crates/bitwarden-core/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs index 7fac112f5..01aede4a8 100644 --- a/crates/bitwarden-core/src/auth/login/mod.rs +++ b/crates/bitwarden-core/src/auth/login/mod.rs @@ -49,7 +49,7 @@ pub(crate) async fn request_prelogin( email: String, ) -> Result { let request_model = PreloginRequestModel::new(email); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; Ok(accounts_prelogin_post(&config.identity, Some(request_model)).await?) } diff --git a/crates/bitwarden-core/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs index e0cb67dbe..f72ef78ac 100644 --- a/crates/bitwarden-core/src/auth/login/password.rs +++ b/crates/bitwarden-core/src/auth/login/password.rs @@ -39,21 +39,25 @@ pub(crate) async fn login_password( let response = request_identity_tokens(client, input, &password_hash).await?; if let IdentityTokenResponse::Authenticated(r) = &response { - client.set_tokens( + client.internal.set_tokens( r.access_token.clone(), r.refresh_token.clone(), r.expires_in, ); - client.set_login_method(LoginMethod::User(UserLoginMethod::Username { - client_id: "web".to_owned(), - email: input.email.to_owned(), - kdf: input.kdf.to_owned(), - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::Username { + client_id: "web".to_owned(), + email: input.email.to_owned(), + kdf: input.kdf.to_owned(), + })); let user_key: EncString = require!(r.key.as_deref()).parse()?; let private_key: EncString = require!(r.private_key.as_deref()).parse()?; - client.initialize_user_crypto_master_key(master_key, user_key, private_key)?; + client + .internal + .initialize_user_crypto_master_key(master_key, user_key, private_key)?; } PasswordLoginResponse::process_response(response) @@ -67,7 +71,7 @@ async fn request_identity_tokens( ) -> Result { use crate::client::client_settings::DeviceType; - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; PasswordTokenRequest::new( &input.email, password_hash, diff --git a/crates/bitwarden-core/src/auth/login/two_factor.rs b/crates/bitwarden-core/src/auth/login/two_factor.rs index c8f0cc55b..f56896c18 100644 --- a/crates/bitwarden-core/src/auth/login/two_factor.rs +++ b/crates/bitwarden-core/src/auth/login/two_factor.rs @@ -29,7 +29,7 @@ pub(crate) async fn send_two_factor_email( HashPurpose::ServerAuthorization, )?; - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; bitwarden_api_api::apis::two_factor_api::two_factor_send_email_login_post( &config.api, Some(TwoFactorEmailRequestModel { diff --git a/crates/bitwarden-core/src/auth/password/validate.rs b/crates/bitwarden-core/src/auth/password/validate.rs index 537b819ea..ee6789910 100644 --- a/crates/bitwarden-core/src/auth/password/validate.rs +++ b/crates/bitwarden-core/src/auth/password/validate.rs @@ -14,6 +14,7 @@ pub(crate) fn validate_password( password_hash: String, ) -> Result { let login_method = client + .internal .login_method .as_ref() .ok_or(Error::NotAuthenticated)?; @@ -44,6 +45,7 @@ pub(crate) fn validate_password_user_key( encrypted_user_key: String, ) -> Result { let login_method = client + .internal .login_method .as_ref() .ok_or(Error::NotAuthenticated)?; @@ -58,6 +60,7 @@ pub(crate) fn validate_password_user_key( .map_err(|_| "wrong password")?; let enc = client + .internal .get_encryption_settings() .map_err(|_| Error::VaultLocked)?; @@ -87,13 +90,15 @@ mod tests { use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; let mut client = Client::new(None); - client.set_login_method(LoginMethod::User(UserLoginMethod::Username { - email: "test@bitwarden.com".to_string(), - kdf: Kdf::PBKDF2 { - iterations: NonZeroU32::new(100_000).unwrap(), - }, - client_id: "1".to_string(), - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::Username { + email: "test@bitwarden.com".to_string(), + kdf: Kdf::PBKDF2 { + iterations: NonZeroU32::new(100_000).unwrap(), + }, + client_id: "1".to_string(), + })); let password = "password123".to_string(); let password_hash = "7kTqkF1pY/3JeOu73N9kR99fDDe9O1JOZaVc7KH3lsU=".to_string(); @@ -118,11 +123,13 @@ mod tests { iterations: NonZeroU32::new(600_000).unwrap(), }; - client.set_login_method(LoginMethod::User(UserLoginMethod::Username { - email: email.to_string(), - kdf: kdf.clone(), - client_id: "1".to_string(), - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::Username { + email: email.to_string(), + kdf: kdf.clone(), + client_id: "1".to_string(), + })); let master_key = bitwarden_crypto::MasterKey::derive(password.as_bytes(), email.as_bytes(), &kdf) @@ -132,6 +139,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=".parse().unwrap(); client + .internal .initialize_user_crypto_master_key(master_key, user_key.parse().unwrap(), private_key) .unwrap(); @@ -158,11 +166,13 @@ mod tests { iterations: NonZeroU32::new(600_000).unwrap(), }; - client.set_login_method(LoginMethod::User(UserLoginMethod::Username { - email: email.to_string(), - kdf: kdf.clone(), - client_id: "1".to_string(), - })); + client + .internal + .set_login_method(LoginMethod::User(UserLoginMethod::Username { + email: email.to_string(), + kdf: kdf.clone(), + client_id: "1".to_string(), + })); let master_key = bitwarden_crypto::MasterKey::derive(password, email.as_bytes(), &kdf).unwrap(); @@ -171,6 +181,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=".parse().unwrap(); client + .internal .initialize_user_crypto_master_key(master_key, user_key.parse().unwrap(), private_key) .unwrap(); diff --git a/crates/bitwarden-core/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs index 06313d42b..52c4127eb 100644 --- a/crates/bitwarden-core/src/auth/register.rs +++ b/crates/bitwarden-core/src/auth/register.rs @@ -19,7 +19,7 @@ pub struct RegisterRequest { /// Half baked implementation of user registration pub(super) async fn register(client: &mut Client, req: &RegisterRequest) -> Result<()> { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let kdf = Kdf::default(); diff --git a/crates/bitwarden-core/src/auth/renew.rs b/crates/bitwarden-core/src/auth/renew.rs index 783494ae2..0969d3697 100644 --- a/crates/bitwarden-core/src/auth/renew.rs +++ b/crates/bitwarden-core/src/auth/renew.rs @@ -12,7 +12,10 @@ use crate::{ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60; - if let (Some(expires), Some(login_method)) = (&client.token_expires_on, &client.login_method) { + if let (Some(expires), Some(login_method)) = ( + &client.internal.token_expires_on, + &client.internal.login_method, + ) { if Utc::now().timestamp() < expires - TOKEN_RENEW_MARGIN_SECONDS { return Ok(()); } @@ -22,6 +25,7 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { LoginMethod::User(u) => match u { UserLoginMethod::Username { client_id, .. } => { let refresh = client + .internal .refresh_token .as_deref() .ok_or(Error::NotAuthenticated)?; @@ -30,7 +34,7 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { refresh.to_owned(), client_id.to_owned(), ) - .send(&client.__api_configurations) + .send(&client.internal.__api_configurations) .await? } UserLoginMethod::ApiKey { @@ -39,7 +43,7 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { .. } => { ApiTokenRequest::new(client_id, client_secret) - .send(&client.__api_configurations) + .send(&client.internal.__api_configurations) .await? } }, @@ -53,12 +57,14 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { access_token.access_token_id, &access_token.client_secret, ) - .send(&client.__api_configurations) + .send(&client.internal.__api_configurations) .await?; - if let (IdentityTokenResponse::Payload(r), Some(state_file), Ok(enc_settings)) = - (&result, state_file, client.get_encryption_settings()) - { + if let (IdentityTokenResponse::Payload(r), Some(state_file), Ok(enc_settings)) = ( + &result, + state_file, + client.internal.get_encryption_settings(), + ) { if let Some(enc_key) = enc_settings.get_key(&None) { let state = ClientState::new(r.access_token.clone(), enc_key.to_base64()); @@ -73,15 +79,21 @@ pub(crate) async fn renew_token(client: &mut Client) -> Result<()> { match res { IdentityTokenResponse::Refreshed(r) => { - client.set_tokens(r.access_token, r.refresh_token, r.expires_in); + client + .internal + .set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } IdentityTokenResponse::Authenticated(r) => { - client.set_tokens(r.access_token, r.refresh_token, r.expires_in); + client + .internal + .set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } IdentityTokenResponse::Payload(r) => { - client.set_tokens(r.access_token, r.refresh_token, r.expires_in); + client + .internal + .set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } _ => { diff --git a/crates/bitwarden-core/src/auth/tde.rs b/crates/bitwarden-core/src/auth/tde.rs index 02f36583c..d632276db 100644 --- a/crates/bitwarden-core/src/auth/tde.rs +++ b/crates/bitwarden-core/src/auth/tde.rs @@ -31,14 +31,18 @@ pub(super) fn make_register_tde_keys( None }; - client.set_login_method(crate::client::LoginMethod::User( - crate::client::UserLoginMethod::Username { - client_id: "".to_owned(), - email, - kdf: Kdf::default(), - }, - )); - client.initialize_user_crypto_decrypted_key(user_key.0, key_pair.private.clone())?; + client + .internal + .set_login_method(crate::client::LoginMethod::User( + crate::client::UserLoginMethod::Username { + client_id: "".to_owned(), + email, + kdf: Kdf::default(), + }, + )); + client + .internal + .initialize_user_crypto_decrypted_key(user_key.0, key_pair.private.clone())?; Ok(RegisterTdeKeyResponse { private_key: key_pair.private, diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index aba4ebab3..ac9862d64 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -1,10 +1,5 @@ -use std::path::PathBuf; - #[cfg(feature = "internal")] pub use bitwarden_crypto::Kdf; -use bitwarden_crypto::SymmetricCryptoKey; -#[cfg(feature = "internal")] -use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey}; use chrono::Utc; use reqwest::header::{self, HeaderValue}; use uuid::Uuid; @@ -12,76 +7,17 @@ use uuid::Uuid; #[cfg(feature = "internal")] use crate::client::flags::Flags; use crate::{ - auth::AccessToken, - client::{ - client_settings::{ClientSettings, DeviceType}, - encryption_settings::EncryptionSettings, - }, + client::{client_settings::ClientSettings, internal::ApiConfigurations}, error::{Error, Result}, }; -#[derive(Debug)] -pub 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, -} - -#[derive(Debug)] -pub(crate) enum LoginMethod { - #[cfg(feature = "internal")] - User(UserLoginMethod), - // TODO: Organizations supports api key - // Organization(OrganizationLoginMethod), - ServiceAccount(ServiceAccountLoginMethod), -} - -#[derive(Debug)] -#[cfg(feature = "internal")] -pub(crate) enum UserLoginMethod { - Username { - client_id: String, - email: String, - kdf: Kdf, - }, - ApiKey { - client_id: String, - client_secret: String, - - email: String, - kdf: Kdf, - }, -} - -#[derive(Debug)] -pub(crate) enum ServiceAccountLoginMethod { - AccessToken { - access_token: AccessToken, - organization_id: Uuid, - state_file: Option, - }, -} +use super::internal::InternalClient; /// 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, - - #[cfg(feature = "internal")] - flags: Flags, - - /// Use Client::get_api_configurations() to access this. - /// It should only be used directly in renew_token #[doc(hidden)] - pub(crate) __api_configurations: ApiConfigurations, - - encryption_settings: Option, + pub internal: InternalClient, } impl Client { @@ -134,155 +70,22 @@ impl Client { }; Self { - token: None, - refresh_token: None, - token_expires_on: None, - login_method: None, - #[cfg(feature = "internal")] - flags: Flags::default(), - __api_configurations: ApiConfigurations { - identity, - api, - external_client, - device_type: settings.device_type, + internal: InternalClient { + token: None, + refresh_token: None, + token_expires_on: None, + login_method: None, + #[cfg(feature = "internal")] + flags: Flags::default(), + + __api_configurations: ApiConfigurations { + identity, + api, + external_client, + device_type: settings.device_type, + }, + encryption_settings: None, }, - encryption_settings: None, - } - } - - #[cfg(feature = "internal")] - pub fn load_flags(&mut self, flags: std::collections::HashMap) { - self.flags = Flags::load_from_map(flags); - } - - #[cfg(feature = "internal")] - pub(crate) fn get_flags(&self) -> &Flags { - &self.flags - } - - pub async fn get_api_configurations(&mut self) -> &ApiConfigurations { - // 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 - } - - #[cfg(feature = "internal")] - pub fn get_http_client(&self) -> &reqwest::Client { - &self.__api_configurations.external_client - } - - #[cfg(feature = "internal")] - pub(crate) fn get_login_method(&self) -> &Option { - &self.login_method - } - - pub fn get_access_token_organization(&self) -> Option { - match self.login_method { - Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { - organization_id, - .. - })) => Some(organization_id), - _ => None, - } - } - - pub fn get_encryption_settings(&self) -> Result<&EncryptionSettings> { - self.encryption_settings.as_ref().ok_or(Error::VaultLocked) - } - - pub(crate) fn set_login_method(&mut self, login_method: LoginMethod) { - use log::debug; - - debug! {"setting login method: {:#?}", login_method} - self.login_method = Some(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); - } - - #[cfg(feature = "internal")] - pub fn is_authed(&self) -> bool { - self.token.is_some() || self.login_method.is_some() - } - - #[cfg(feature = "internal")] - pub(crate) fn initialize_user_crypto_master_key( - &mut self, - master_key: MasterKey, - user_key: EncString, - private_key: EncString, - ) -> Result<&EncryptionSettings> { - Ok(self.encryption_settings.insert(EncryptionSettings::new( - master_key, - user_key, - private_key, - )?)) - } - - #[cfg(feature = "internal")] - pub(crate) fn initialize_user_crypto_decrypted_key( - &mut self, - user_key: SymmetricCryptoKey, - private_key: EncString, - ) -> Result<&EncryptionSettings> { - Ok(self - .encryption_settings - .insert(EncryptionSettings::new_decrypted_key( - user_key, - private_key, - )?)) - } - - #[cfg(feature = "internal")] - pub(crate) fn initialize_user_crypto_pin( - &mut self, - pin_key: MasterKey, - pin_protected_user_key: EncString, - private_key: EncString, - ) -> Result<&EncryptionSettings> { - 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)) - } - - #[cfg(feature = "internal")] - pub(crate) fn initialize_org_crypto( - &mut self, - org_keys: Vec<(Uuid, AsymmetricEncString)>, - ) -> Result<&EncryptionSettings> { - let enc = self - .encryption_settings - .as_mut() - .ok_or(Error::VaultLocked)?; - - enc.set_org_keys(org_keys)?; - Ok(&*enc) - } - - pub fn get_kdf(&self) -> Result { - match &self.login_method { - Some(LoginMethod::User( - UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, - )) => Ok(kdf.clone()), - _ => Err(Error::NotAuthenticated), } } } diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs new file mode 100644 index 000000000..a7d697475 --- /dev/null +++ b/crates/bitwarden-core/src/client/internal.rs @@ -0,0 +1,183 @@ +use crate::{ + error::{Error, Result}, + DeviceType, +}; + +use super::{ + encryption_settings::EncryptionSettings, + flags::Flags, + login_method::{LoginMethod, ServiceAccountLoginMethod, UserLoginMethod}, +}; + +use bitwarden_crypto::Kdf; +#[cfg(feature = "internal")] +use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey, SymmetricCryptoKey}; +use chrono::Utc; +#[cfg(feature = "internal")] +use uuid::Uuid; + +#[derive(Debug)] +pub 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, +} + +#[derive(Debug)] +pub struct InternalClient { + pub(super) token: Option, + pub(crate) refresh_token: Option, + pub(crate) token_expires_on: Option, + pub(crate) login_method: Option, + + #[cfg(feature = "internal")] + pub(super) flags: Flags, + + /// 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(super) encryption_settings: Option, +} + +impl InternalClient { + #[cfg(feature = "internal")] + pub fn load_flags(&mut self, flags: std::collections::HashMap) { + self.flags = Flags::load_from_map(flags); + } + + #[cfg(feature = "internal")] + pub(crate) fn get_flags(&self) -> &Flags { + &self.flags + } + + #[cfg(feature = "internal")] + pub(crate) fn get_login_method(&self) -> &Option { + &self.login_method + } + + pub fn get_access_token_organization(&self) -> Option { + match self.login_method { + Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { + organization_id, + .. + })) => Some(organization_id), + _ => None, + } + } + + pub(crate) fn set_login_method(&mut self, login_method: LoginMethod) { + use log::debug; + + debug! {"setting login method: {:#?}", login_method} + self.login_method = Some(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); + } + + #[cfg(feature = "internal")] + pub fn is_authed(&self) -> bool { + self.token.is_some() || self.login_method.is_some() + } + + pub fn get_kdf(&self) -> Result { + match &self.login_method { + Some(LoginMethod::User( + UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, + )) => Ok(kdf.clone()), + _ => Err(Error::NotAuthenticated), + } + } + + pub async fn get_api_configurations(&mut self) -> &ApiConfigurations { + // 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 + } + + #[cfg(feature = "internal")] + pub fn get_http_client(&self) -> &reqwest::Client { + &self.__api_configurations.external_client + } + + pub fn get_encryption_settings(&self) -> Result<&EncryptionSettings> { + self.encryption_settings.as_ref().ok_or(Error::VaultLocked) + } + + #[cfg(feature = "internal")] + pub(crate) fn initialize_user_crypto_master_key( + &mut self, + master_key: MasterKey, + user_key: EncString, + private_key: EncString, + ) -> Result<&EncryptionSettings> { + Ok(self.encryption_settings.insert(EncryptionSettings::new( + master_key, + user_key, + private_key, + )?)) + } + + #[cfg(feature = "internal")] + pub(crate) fn initialize_user_crypto_decrypted_key( + &mut self, + user_key: SymmetricCryptoKey, + private_key: EncString, + ) -> Result<&EncryptionSettings> { + Ok(self + .encryption_settings + .insert(EncryptionSettings::new_decrypted_key( + user_key, + private_key, + )?)) + } + + #[cfg(feature = "internal")] + pub(crate) fn initialize_user_crypto_pin( + &mut self, + pin_key: MasterKey, + pin_protected_user_key: EncString, + private_key: EncString, + ) -> Result<&EncryptionSettings> { + 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)) + } + + #[cfg(feature = "internal")] + pub(crate) fn initialize_org_crypto( + &mut self, + org_keys: Vec<(Uuid, AsymmetricEncString)>, + ) -> Result<&EncryptionSettings> { + let enc = self + .encryption_settings + .as_mut() + .ok_or(Error::VaultLocked)?; + + enc.set_org_keys(org_keys)?; + Ok(&*enc) + } +} diff --git a/crates/bitwarden-core/src/client/login_method.rs b/crates/bitwarden-core/src/client/login_method.rs new file mode 100644 index 000000000..e39ad7818 --- /dev/null +++ b/crates/bitwarden-core/src/client/login_method.rs @@ -0,0 +1,41 @@ +use std::path::PathBuf; + +use bitwarden_crypto::Kdf; +use uuid::Uuid; + +use crate::auth::AccessToken; + +#[derive(Debug)] +pub(crate) enum LoginMethod { + #[cfg(feature = "internal")] + User(UserLoginMethod), + // TODO: Organizations supports api key + // Organization(OrganizationLoginMethod), + ServiceAccount(ServiceAccountLoginMethod), +} + +#[derive(Debug)] +#[cfg(feature = "internal")] +pub(crate) enum UserLoginMethod { + Username { + client_id: String, + email: String, + kdf: Kdf, + }, + ApiKey { + client_id: String, + client_secret: String, + + email: String, + kdf: Kdf, + }, +} + +#[derive(Debug)] +pub(crate) enum ServiceAccountLoginMethod { + AccessToken { + access_token: AccessToken, + organization_id: Uuid, + state_file: Option, + }, +} diff --git a/crates/bitwarden-core/src/client/mod.rs b/crates/bitwarden-core/src/client/mod.rs index 9e5543d98..d19e2d949 100644 --- a/crates/bitwarden-core/src/client/mod.rs +++ b/crates/bitwarden-core/src/client/mod.rs @@ -5,6 +5,10 @@ pub(crate) use client::*; mod client; pub mod client_settings; pub mod encryption_settings; +pub mod internal; +pub use internal::ApiConfigurations; +pub mod login_method; +pub(crate) use login_method::{LoginMethod, ServiceAccountLoginMethod, UserLoginMethod}; #[cfg(feature = "internal")] mod flags; diff --git a/crates/bitwarden-core/src/mobile/crypto.rs b/crates/bitwarden-core/src/mobile/crypto.rs index ad48656a6..6d78820f2 100644 --- a/crates/bitwarden-core/src/mobile/crypto.rs +++ b/crates/bitwarden-core/src/mobile/crypto.rs @@ -98,18 +98,26 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ let master_key = MasterKey::derive(password.as_bytes(), req.email.as_bytes(), &req.kdf_params)?; - client.initialize_user_crypto_master_key(master_key, user_key, private_key)?; + client + .internal + .initialize_user_crypto_master_key(master_key, user_key, private_key)?; } InitUserCryptoMethod::DecryptedKey { decrypted_user_key } => { let user_key = SymmetricCryptoKey::try_from(decrypted_user_key)?; - client.initialize_user_crypto_decrypted_key(user_key, private_key)?; + client + .internal + .initialize_user_crypto_decrypted_key(user_key, private_key)?; } InitUserCryptoMethod::Pin { pin, pin_protected_user_key, } => { let pin_key = MasterKey::derive(pin.as_bytes(), req.email.as_bytes(), &req.kdf_params)?; - client.initialize_user_crypto_pin(pin_key, pin_protected_user_key, private_key)?; + client.internal.initialize_user_crypto_pin( + pin_key, + pin_protected_user_key, + private_key, + )?; } InitUserCryptoMethod::AuthRequest { request_private_key, @@ -128,7 +136,9 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ auth_request_key, )?, }; - client.initialize_user_crypto_decrypted_key(user_key, private_key)?; + client + .internal + .initialize_user_crypto_decrypted_key(user_key, private_key)?; } InitUserCryptoMethod::DeviceKey { device_key, @@ -139,17 +149,21 @@ pub async fn initialize_user_crypto(client: &mut Client, req: InitUserCryptoRequ let user_key = device_key .decrypt_user_key(protected_device_private_key, device_protected_user_key)?; - client.initialize_user_crypto_decrypted_key(user_key, private_key)?; + client + .internal + .initialize_user_crypto_decrypted_key(user_key, private_key)?; } } - client.set_login_method(crate::client::LoginMethod::User( - crate::client::UserLoginMethod::Username { - client_id: "".to_string(), - email: req.email, - kdf: req.kdf_params, - }, - )); + client + .internal + .set_login_method(crate::client::LoginMethod::User( + crate::client::UserLoginMethod::Username { + client_id: "".to_string(), + email: req.email, + kdf: req.kdf_params, + }, + )); Ok(()) } @@ -166,13 +180,14 @@ pub struct InitOrgCryptoRequest { #[cfg(feature = "internal")] pub async fn initialize_org_crypto(client: &mut Client, req: InitOrgCryptoRequest) -> Result<()> { let organization_keys = req.organization_keys.into_iter().collect(); - client.initialize_org_crypto(organization_keys)?; + client.internal.initialize_org_crypto(organization_keys)?; Ok(()) } #[cfg(feature = "internal")] pub async fn get_user_encryption_key(client: &mut Client) -> Result { let user_key = client + .internal .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; @@ -196,11 +211,13 @@ pub fn update_password( new_password: String, ) -> Result { let user_key = client + .internal .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; let login_method = client + .internal .login_method .as_ref() .ok_or(Error::NotAuthenticated)?; @@ -241,11 +258,13 @@ pub struct DerivePinKeyResponse { #[cfg(feature = "internal")] pub fn derive_pin_key(client: &mut Client, pin: String) -> Result { let user_key = client + .internal .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; let login_method = client + .internal .login_method .as_ref() .ok_or(Error::NotAuthenticated)?; @@ -261,12 +280,14 @@ pub fn derive_pin_key(client: &mut Client, pin: String) -> Result Result { let user_key = client + .internal .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; let pin: String = encrypted_pin.decrypt_with_key(user_key)?; let login_method = client + .internal .login_method .as_ref() .ok_or(Error::NotAuthenticated)?; @@ -300,7 +321,7 @@ pub(super) fn enroll_admin_password_reset( use bitwarden_crypto::AsymmetricPublicCryptoKey; let public_key = AsymmetricPublicCryptoKey::from_der(&STANDARD.decode(public_key)?)?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; Ok(AsymmetricEncString::encrypt_rsa2048_oaep_sha1( @@ -373,12 +394,14 @@ mod tests { assert_eq!( client + .internal .get_encryption_settings() .unwrap() .get_key(&None) .unwrap() .to_base64(), client2 + .internal .get_encryption_settings() .unwrap() .get_key(&None) @@ -433,12 +456,14 @@ mod tests { assert_eq!( client + .internal .get_encryption_settings() .unwrap() .get_key(&None) .unwrap() .to_base64(), client2 + .internal .get_encryption_settings() .unwrap() .get_key(&None) @@ -471,12 +496,14 @@ mod tests { assert_eq!( client + .internal .get_encryption_settings() .unwrap() .get_key(&None) .unwrap() .to_base64(), client3 + .internal .get_encryption_settings() .unwrap() .get_key(&None) @@ -507,6 +534,7 @@ mod tests { let user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap(); 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=".parse().unwrap(); client + .internal .initialize_user_crypto_master_key(master_key, user_key, private_key) .unwrap(); @@ -520,6 +548,7 @@ mod tests { let decrypted: Vec = encrypted.decrypt_with_key(&private_key).unwrap(); let expected = client + .internal .get_encryption_settings() .unwrap() .get_key(&None) diff --git a/crates/bitwarden-core/src/mobile/vault/client_attachments.rs b/crates/bitwarden-core/src/mobile/vault/client_attachments.rs index 20dcf0c13..97798a18d 100644 --- a/crates/bitwarden-core/src/mobile/vault/client_attachments.rs +++ b/crates/bitwarden-core/src/mobile/vault/client_attachments.rs @@ -22,7 +22,7 @@ impl<'a> ClientAttachments<'a> { attachment: AttachmentView, buffer: &[u8], ) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = cipher.locate_key(enc, &None).ok_or(Error::VaultLocked)?; Ok(AttachmentFileView { @@ -54,7 +54,7 @@ impl<'a> ClientAttachments<'a> { attachment: Attachment, encrypted_buffer: &[u8], ) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = cipher.locate_key(enc, &None).ok_or(Error::VaultLocked)?; AttachmentFile { diff --git a/crates/bitwarden-core/src/mobile/vault/client_ciphers.rs b/crates/bitwarden-core/src/mobile/vault/client_ciphers.rs index b0760702f..4f0b4342e 100644 --- a/crates/bitwarden-core/src/mobile/vault/client_ciphers.rs +++ b/crates/bitwarden-core/src/mobile/vault/client_ciphers.rs @@ -13,11 +13,17 @@ pub struct ClientCiphers<'a> { impl<'a> ClientCiphers<'a> { pub async fn encrypt(&self, mut cipher_view: CipherView) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; // 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 { + if cipher_view.key.is_none() + && self + .client + .internal + .get_flags() + .enable_cipher_key_encryption + { let key = cipher_view .locate_key(enc, &None) .ok_or(Error::VaultLocked)?; @@ -33,7 +39,7 @@ impl<'a> ClientCiphers<'a> { } pub async fn decrypt(&self, cipher: Cipher) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = cipher .locate_key(enc, &None) .ok_or(CryptoError::MissingKey)?; @@ -44,7 +50,7 @@ impl<'a> ClientCiphers<'a> { } pub async fn decrypt_list(&self, ciphers: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let cipher_views: Result> = ciphers .iter() @@ -62,7 +68,7 @@ impl<'a> ClientCiphers<'a> { mut cipher_view: CipherView, organization_id: Uuid, ) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; cipher_view.move_to_organization(enc, organization_id)?; Ok(cipher_view) } diff --git a/crates/bitwarden-core/src/mobile/vault/client_collection.rs b/crates/bitwarden-core/src/mobile/vault/client_collection.rs index 878db238f..09ffbaf4a 100644 --- a/crates/bitwarden-core/src/mobile/vault/client_collection.rs +++ b/crates/bitwarden-core/src/mobile/vault/client_collection.rs @@ -12,7 +12,7 @@ pub struct ClientCollections<'a> { impl<'a> ClientCollections<'a> { pub async fn decrypt(&self, collection: Collection) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = collection .locate_key(enc, &None) .ok_or(CryptoError::MissingKey)?; @@ -23,7 +23,7 @@ impl<'a> ClientCollections<'a> { } pub async fn decrypt_list(&self, collections: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let views: Result> = collections .iter() diff --git a/crates/bitwarden-core/src/mobile/vault/client_folders.rs b/crates/bitwarden-core/src/mobile/vault/client_folders.rs index 9d396d9e1..d0b0f777b 100644 --- a/crates/bitwarden-core/src/mobile/vault/client_folders.rs +++ b/crates/bitwarden-core/src/mobile/vault/client_folders.rs @@ -12,7 +12,7 @@ pub struct ClientFolders<'a> { impl<'a> ClientFolders<'a> { pub async fn encrypt(&self, folder_view: FolderView) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(CryptoError::MissingKey)?; let folder = folder_view.encrypt_with_key(key)?; @@ -21,7 +21,7 @@ impl<'a> ClientFolders<'a> { } pub async fn decrypt(&self, folder: Folder) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(CryptoError::MissingKey)?; let folder_view = folder.decrypt_with_key(key)?; @@ -30,7 +30,7 @@ impl<'a> ClientFolders<'a> { } pub async fn decrypt_list(&self, folders: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(CryptoError::MissingKey)?; let views = folders.decrypt_with_key(key)?; diff --git a/crates/bitwarden-core/src/mobile/vault/client_password_history.rs b/crates/bitwarden-core/src/mobile/vault/client_password_history.rs index 734969127..654a60b0b 100644 --- a/crates/bitwarden-core/src/mobile/vault/client_password_history.rs +++ b/crates/bitwarden-core/src/mobile/vault/client_password_history.rs @@ -12,7 +12,7 @@ pub struct ClientPasswordHistory<'a> { impl<'a> ClientPasswordHistory<'a> { pub async fn encrypt(&self, history_view: PasswordHistoryView) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(CryptoError::MissingKey)?; let history = history_view.encrypt_with_key(key)?; @@ -24,7 +24,7 @@ impl<'a> ClientPasswordHistory<'a> { &self, history: Vec, ) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(CryptoError::MissingKey)?; let history_view = history.decrypt_with_key(key)?; diff --git a/crates/bitwarden-core/src/platform/fido2/authenticator.rs b/crates/bitwarden-core/src/platform/fido2/authenticator.rs index 69aae6f0c..16112b51c 100644 --- a/crates/bitwarden-core/src/platform/fido2/authenticator.rs +++ b/crates/bitwarden-core/src/platform/fido2/authenticator.rs @@ -245,7 +245,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { .find_credentials(ids, rp_id.to_string()) .await?; - let enc = this.authenticator.client.get_encryption_settings()?; + let enc = this + .authenticator + .client + .internal + .get_encryption_settings()?; // Remove any that don't have Fido2 credentials let creds: Vec<_> = ciphers @@ -304,7 +308,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { user: passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, ) -> Result<()> { - let enc = this.authenticator.client.get_encryption_settings()?; + let enc = this + .authenticator + .client + .internal + .get_encryption_settings()?; let cred = Fido2CredentialFullView::try_from_credential(cred, user, rp)?; @@ -344,7 +352,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { async fn update_credential(&mut self, cred: Passkey) -> Result<(), StatusCode> { // This is just a wrapper around the actual implementation to allow for ? error handling async fn inner(this: &mut CredentialStoreImpl<'_>, cred: Passkey) -> Result<()> { - let enc = this.authenticator.client.get_encryption_settings()?; + let enc = this + .authenticator + .client + .internal + .get_encryption_settings()?; // Get the previously selected cipher and update the credential let selected = this.authenticator.get_selected_credential()?; diff --git a/crates/bitwarden-core/src/platform/generate_fingerprint.rs b/crates/bitwarden-core/src/platform/generate_fingerprint.rs index d62eb5436..662a4a85f 100644 --- a/crates/bitwarden-core/src/platform/generate_fingerprint.rs +++ b/crates/bitwarden-core/src/platform/generate_fingerprint.rs @@ -38,7 +38,7 @@ pub(crate) fn generate_user_fingerprint( ) -> Result { info!("Generating fingerprint"); - let enc_settings = client.get_encryption_settings()?; + let enc_settings = client.internal.get_encryption_settings()?; let private_key = enc_settings .private_key .as_ref() @@ -75,6 +75,7 @@ mod tests { .unwrap(); client + .internal .initialize_user_crypto_master_key( master_key, user_key.parse().unwrap(), diff --git a/crates/bitwarden-core/src/platform/get_user_api_key.rs b/crates/bitwarden-core/src/platform/get_user_api_key.rs index 3e408d926..76085da72 100644 --- a/crates/bitwarden-core/src/platform/get_user_api_key.rs +++ b/crates/bitwarden-core/src/platform/get_user_api_key.rs @@ -24,15 +24,16 @@ pub(crate) async fn get_user_api_key( let auth_settings = get_login_method(client)?; let request = get_secret_verification_request(auth_settings, input)?; - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let response = accounts_api_key_post(&config.api, Some(request)).await?; UserApiKeyResponse::process_response(response) } fn get_login_method(client: &Client) -> Result<&LoginMethod> { - if client.is_authed() { + if client.internal.is_authed() { client + .internal .get_login_method() .as_ref() .ok_or(Error::NotAuthenticated) diff --git a/crates/bitwarden-core/src/vault/sync.rs b/crates/bitwarden-core/src/vault/sync.rs index 792004931..78f641d04 100644 --- a/crates/bitwarden-core/src/vault/sync.rs +++ b/crates/bitwarden-core/src/vault/sync.rs @@ -21,7 +21,7 @@ pub struct SyncRequest { } pub(crate) async fn sync(client: &mut Client, input: &SyncRequest) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let sync = bitwarden_api_api::apis::sync_api::sync_get(&config.api, input.exclude_subdomains).await?; @@ -33,7 +33,7 @@ pub(crate) async fn sync(client: &mut Client, input: &SyncRequest) -> Result, format: ExportFormat, ) -> Result { - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; let folders: Vec = folders.decrypt_with_key(key)?; @@ -34,7 +34,7 @@ pub(crate) fn export_vault( folders, ciphers, password, - client.get_kdf()?, + client.internal.get_kdf()?, )?), } } diff --git a/crates/bitwarden-generators/src/client_generator.rs b/crates/bitwarden-generators/src/client_generator.rs index 0cf4e4296..2b3d88ef2 100644 --- a/crates/bitwarden-generators/src/client_generator.rs +++ b/crates/bitwarden-generators/src/client_generator.rs @@ -87,7 +87,7 @@ impl<'a> ClientGenerator<'a> { /// } /// ``` pub async fn username(&self, input: UsernameGeneratorRequest) -> Result { - username(input, self.client.get_http_client()).await + username(input, self.client.internal.get_http_client()).await } } diff --git a/crates/bitwarden-send/src/client_sends.rs b/crates/bitwarden-send/src/client_sends.rs index 2833e1881..ec3419da0 100644 --- a/crates/bitwarden-send/src/client_sends.rs +++ b/crates/bitwarden-send/src/client_sends.rs @@ -18,7 +18,7 @@ impl<'a> ClientSends<'a> { } pub async fn decrypt(&self, send: Send) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; let send_view = send.decrypt_with_key(key)?; @@ -27,7 +27,7 @@ impl<'a> ClientSends<'a> { } pub async fn decrypt_list(&self, sends: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; let send_views = sends.decrypt_with_key(key)?; @@ -48,7 +48,7 @@ impl<'a> ClientSends<'a> { } pub async fn decrypt_buffer(&self, send: Send, encrypted_buffer: &[u8]) -> Result> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; let key = Send::get_key(&send.key, key)?; @@ -57,7 +57,7 @@ impl<'a> ClientSends<'a> { } pub async fn encrypt(&self, send_view: SendView) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(Error::VaultLocked)?; let send = send_view.encrypt_with_key(key)?; @@ -80,6 +80,7 @@ impl<'a> ClientSends<'a> { pub async fn encrypt_buffer(&self, send: Send, buffer: &[u8]) -> Result> { let key = self .client + .internal .get_encryption_settings()? .get_key(&None) .ok_or(Error::VaultLocked)?; diff --git a/crates/bitwarden-sm/src/projects/create.rs b/crates/bitwarden-sm/src/projects/create.rs index dda8af28d..d2fa4ef0f 100644 --- a/crates/bitwarden-sm/src/projects/create.rs +++ b/crates/bitwarden-sm/src/projects/create.rs @@ -21,6 +21,7 @@ pub(crate) async fn create_project( input: &ProjectCreateRequest, ) -> Result { let key = client + .internal .get_encryption_settings()? .get_key(&Some(input.organization_id)) .ok_or(Error::VaultLocked)?; @@ -29,7 +30,7 @@ pub(crate) async fn create_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_post( &config.api, input.organization_id, @@ -37,7 +38,7 @@ pub(crate) async fn create_project( ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; ProjectResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs index 34e82feae..36252ed53 100644 --- a/crates/bitwarden-sm/src/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_projects( client: &mut Client, input: ProjectsDeleteRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs index 4098f19df..5502d3968 100644 --- a/crates/bitwarden-sm/src/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -16,11 +16,11 @@ pub(crate) async fn get_project( client: &mut Client, input: &ProjectGetRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_id_get(&config.api, input.id).await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; ProjectResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs index 16c4501e1..0379eb8b8 100644 --- a/crates/bitwarden-sm/src/projects/list.rs +++ b/crates/bitwarden-sm/src/projects/list.rs @@ -20,14 +20,14 @@ pub(crate) async fn list_projects( client: &mut Client, input: &ProjectsListRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_get( &config.api, input.organization_id, ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; ProjectsResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs index b5249a2ff..e7a60193d 100644 --- a/crates/bitwarden-sm/src/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -26,6 +26,7 @@ pub(crate) async fn update_project( input: &ProjectPutRequest, ) -> Result { let key = client + .internal .get_encryption_settings()? .get_key(&Some(input.organization_id)) .ok_or(Error::VaultLocked)?; @@ -34,12 +35,12 @@ pub(crate) async fn update_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_id_put(&config.api, input.id, project) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; ProjectResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs index 50a6fe2ca..a3ca89e0a 100644 --- a/crates/bitwarden-sm/src/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -29,6 +29,7 @@ pub(crate) async fn create_secret( input: &SecretCreateRequest, ) -> Result { let key = client + .internal .get_encryption_settings()? .get_key(&Some(input.organization_id)) .ok_or(Error::VaultLocked)?; @@ -40,7 +41,7 @@ pub(crate) async fn create_secret( project_ids: input.project_ids.clone(), }); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_post( &config.api, input.organization_id, @@ -48,7 +49,7 @@ pub(crate) async fn create_secret( ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs index 028f2c53a..3d55a3abd 100644 --- a/crates/bitwarden-sm/src/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_secrets( client: &mut Client, input: SecretsDeleteRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs index 008040d64..0c32e4944 100644 --- a/crates/bitwarden-sm/src/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -16,10 +16,10 @@ pub(crate) async fn get_secret( client: &mut Client, input: &SecretGetRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_id_get(&config.api, input.id).await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs index 50a7612a9..a0ff6111c 100644 --- a/crates/bitwarden-sm/src/secrets/get_by_ids.rs +++ b/crates/bitwarden-sm/src/secrets/get_by_ids.rs @@ -19,12 +19,12 @@ pub(crate) async fn get_secrets_by_ids( ) -> Result { let request = Some(GetSecretsRequestModel { ids: input.ids }); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_get_by_ids_post(&config.api, request).await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretsResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs index 73ca2e5c3..e6a86c558 100644 --- a/crates/bitwarden-sm/src/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -22,14 +22,14 @@ pub(crate) async fn list_secrets( client: &mut Client, input: &SecretIdentifiersRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_get( &config.api, input.organization_id, ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretIdentifiersResponse::process_response(res, enc) } @@ -45,14 +45,14 @@ pub(crate) async fn list_secrets_by_project( client: &mut Client, input: &SecretIdentifiersByProjectRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::projects_project_id_secrets_get( &config.api, input.project_id, ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretIdentifiersResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs index 61d526d12..474cb859f 100644 --- a/crates/bitwarden-sm/src/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -22,7 +22,7 @@ pub(crate) async fn sync_secrets( client: &mut Client, input: &SecretsSyncRequest, ) -> Result { - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let last_synced_date = input.last_synced_date.map(|date| date.to_rfc3339()); let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_sync_get( @@ -32,7 +32,7 @@ pub(crate) async fn sync_secrets( ) .await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretsSyncResponse::process_response(res, enc) } diff --git a/crates/bitwarden-sm/src/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs index e4bcaff1b..c34366b54 100644 --- a/crates/bitwarden-sm/src/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -29,6 +29,7 @@ pub(crate) async fn update_secret( input: &SecretPutRequest, ) -> Result { let key = client + .internal .get_encryption_settings()? .get_key(&Some(input.organization_id)) .ok_or(Error::VaultLocked)?; @@ -40,11 +41,11 @@ pub(crate) async fn update_secret( project_ids: input.project_ids.clone(), }); - let config = client.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_id_put(&config.api, input.id, secret).await?; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; SecretResponse::process_response(res, enc) } diff --git a/crates/bitwarden-uniffi/src/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index 458306676..1a3be09d1 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -36,7 +36,7 @@ impl ClientPlatform { /// 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); + self.0 .0.write().await.internal.load_flags(flags); Ok(()) } diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 4d2f5db18..f25886552 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -137,7 +137,7 @@ async fn process_commands() -> Result<()> { }) .await?; - let organization_id = match client.get_access_token_organization() { + let organization_id = match client.internal.get_access_token_organization() { Some(id) => id, None => { error!("Access token isn't associated to an organization."); From 3c996db48d59eba4ac30e1c41cd32d76827ac511 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 10 Jun 2024 15:00:10 +0200 Subject: [PATCH 08/28] fmt --- .../src/admin_console/policy.rs | 6 ++++-- .../src/auth/login/access_token.rs | 2 +- .../bitwarden-core/src/auth/login/api_key.rs | 3 +-- .../src/auth/login/auth_request.rs | 3 +-- .../bitwarden-core/src/auth/login/password.rs | 3 +-- crates/bitwarden-core/src/client/client.rs | 3 +-- crates/bitwarden-core/src/client/internal.rs | 21 +++++++++---------- .../src/platform/get_user_api_key.rs | 3 +-- .../bitwarden-core/src/vault/cipher/cipher.rs | 2 +- .../bitwarden-core/src/vault/cipher/field.rs | 6 ++++-- .../src/vault/cipher/linked_id.rs | 3 ++- .../bitwarden-core/src/vault/cipher/login.rs | 6 ++++-- .../src/vault/cipher/secure_note.rs | 6 ++++-- crates/bitwarden-core/src/vault/collection.rs | 6 ++++-- crates/bitwarden-core/src/vault/domain.rs | 6 ++++-- crates/bitwarden-core/src/vault/folder.rs | 6 ++++-- crates/bitwarden-core/src/vault/sync.rs | 2 +- crates/bitwarden-exporters/src/models.rs | 2 +- 18 files changed, 49 insertions(+), 40 deletions(-) diff --git a/crates/bitwarden-core/src/admin_console/policy.rs b/crates/bitwarden-core/src/admin_console/policy.rs index 64c4f1ada..cde09c24c 100644 --- a/crates/bitwarden-core/src/admin_console/policy.rs +++ b/crates/bitwarden-core/src/admin_console/policy.rs @@ -1,13 +1,15 @@ use std::collections::HashMap; -use crate::require; use bitwarden_api_api::models::PolicyResponseModel; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] pub struct Policy { diff --git a/crates/bitwarden-core/src/auth/login/access_token.rs b/crates/bitwarden-core/src/auth/login/access_token.rs index cf123df81..990f61ec9 100644 --- a/crates/bitwarden-core/src/auth/login/access_token.rs +++ b/crates/bitwarden-core/src/auth/login/access_token.rs @@ -1,6 +1,5 @@ use std::path::{Path, PathBuf}; -use crate::require; use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; use chrono::Utc; @@ -16,6 +15,7 @@ use crate::{ }, client::{LoginMethod, ServiceAccountLoginMethod}, error::{Error, Result}, + require, secrets_manager::state::{self, ClientState}, Client, }; diff --git a/crates/bitwarden-core/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs index 6b96fc0b7..cc96934fd 100644 --- a/crates/bitwarden-core/src/auth/login/api_key.rs +++ b/crates/bitwarden-core/src/auth/login/api_key.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_crypto::{EncString, MasterKey}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -11,7 +10,7 @@ use crate::{ }, client::{LoginMethod, UserLoginMethod}, error::Result, - Client, + require, Client, }; pub(crate) async fn login_api_key( diff --git a/crates/bitwarden-core/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs index c66cae009..6ebde9bc0 100644 --- a/crates/bitwarden-core/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_api_api::{ apis::auth_requests_api::{auth_requests_id_response_get, auth_requests_post}, models::{AuthRequestCreateRequestModel, AuthRequestType}, @@ -14,7 +13,7 @@ use crate::{ client::{LoginMethod, UserLoginMethod}, error::Result, mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, - Client, + require, Client, }; pub struct NewAuthRequestResponse { diff --git a/crates/bitwarden-core/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs index c1fe48867..0e62c59be 100644 --- a/crates/bitwarden-core/src/auth/login/password.rs +++ b/crates/bitwarden-core/src/auth/login/password.rs @@ -22,10 +22,9 @@ pub(crate) async fn login_password( client: &mut Client, input: &PasswordLoginRequest, ) -> Result { - use crate::require; use bitwarden_crypto::{EncString, HashPurpose, MasterKey}; - use crate::client::UserLoginMethod; + use crate::{client::UserLoginMethod, require}; info!("password logging in"); diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index 733595adc..47d624221 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -2,12 +2,11 @@ pub use bitwarden_crypto::Kdf; use reqwest::header::{self, HeaderValue}; +use super::internal::InternalClient; #[cfg(feature = "internal")] use crate::client::flags::Flags; use crate::client::{client_settings::ClientSettings, internal::ApiConfigurations}; -use super::internal::InternalClient; - /// The main struct to interact with the Bitwarden SDK. #[derive(Debug)] pub struct Client { diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index a7d697475..fe0b22b94 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -1,14 +1,3 @@ -use crate::{ - error::{Error, Result}, - DeviceType, -}; - -use super::{ - encryption_settings::EncryptionSettings, - flags::Flags, - login_method::{LoginMethod, ServiceAccountLoginMethod, UserLoginMethod}, -}; - use bitwarden_crypto::Kdf; #[cfg(feature = "internal")] use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey, SymmetricCryptoKey}; @@ -16,6 +5,16 @@ use chrono::Utc; #[cfg(feature = "internal")] use uuid::Uuid; +use super::{ + encryption_settings::EncryptionSettings, + flags::Flags, + login_method::{LoginMethod, ServiceAccountLoginMethod, UserLoginMethod}, +}; +use crate::{ + error::{Error, Result}, + DeviceType, +}; + #[derive(Debug)] pub struct ApiConfigurations { pub identity: bitwarden_api_identity::apis::configuration::Configuration, diff --git a/crates/bitwarden-core/src/platform/get_user_api_key.rs b/crates/bitwarden-core/src/platform/get_user_api_key.rs index 89c126c34..2db3e5cad 100644 --- a/crates/bitwarden-core/src/platform/get_user_api_key.rs +++ b/crates/bitwarden-core/src/platform/get_user_api_key.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_api_api::{ apis::accounts_api::accounts_api_key_post, models::{ApiKeyResponseModel, SecretVerificationRequestModel}, @@ -12,7 +11,7 @@ use super::SecretVerificationRequest; use crate::{ client::{LoginMethod, UserLoginMethod}, error::{Error, Result}, - Client, + require, Client, }; pub(crate) async fn get_user_api_key( diff --git a/crates/bitwarden-core/src/vault/cipher/cipher.rs b/crates/bitwarden-core/src/vault/cipher/cipher.rs index e2d83a5cc..32dee642a 100644 --- a/crates/bitwarden-core/src/vault/cipher/cipher.rs +++ b/crates/bitwarden-core/src/vault/cipher/cipher.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_api_api::models::CipherDetailsResponseModel; use bitwarden_crypto::{ CryptoError, EncString, KeyContainer, KeyDecryptable, KeyEncryptable, LocateKey, @@ -19,6 +18,7 @@ use super::{ use crate::{client::encryption_settings::EncryptionSettings, vault::Fido2CredentialView}; use crate::{ error::{Error, Result}, + require, vault::{password_history, Fido2CredentialFullView}, }; diff --git a/crates/bitwarden-core/src/vault/cipher/field.rs b/crates/bitwarden-core/src/vault/cipher/field.rs index a424c7c00..c8b2701d4 100644 --- a/crates/bitwarden-core/src/vault/cipher/field.rs +++ b/crates/bitwarden-core/src/vault/cipher/field.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_api_api::models::CipherFieldModel; use bitwarden_crypto::{ CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, @@ -8,7 +7,10 @@ use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use super::linked_id::LinkedIdType; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema)] #[repr(u8)] diff --git a/crates/bitwarden-core/src/vault/cipher/linked_id.rs b/crates/bitwarden-core/src/vault/cipher/linked_id.rs index 3b25ab856..b523b3947 100644 --- a/crates/bitwarden-core/src/vault/cipher/linked_id.rs +++ b/crates/bitwarden-core/src/vault/cipher/linked_id.rs @@ -1,8 +1,9 @@ -use crate::MissingFieldError; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; +use crate::MissingFieldError; + #[derive(Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Debug, JsonSchema)] #[serde(untagged)] pub enum LinkedIdType { diff --git a/crates/bitwarden-core/src/vault/cipher/login.rs b/crates/bitwarden-core/src/vault/cipher/login.rs index 085f59982..51e2a53d8 100644 --- a/crates/bitwarden-core/src/vault/cipher/login.rs +++ b/crates/bitwarden-core/src/vault/cipher/login.rs @@ -1,4 +1,3 @@ -use crate::require; use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_api_api::models::{CipherLoginModel, CipherLoginUriModel}; use bitwarden_crypto::{ @@ -9,7 +8,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema)] #[repr(u8)] diff --git a/crates/bitwarden-core/src/vault/cipher/secure_note.rs b/crates/bitwarden-core/src/vault/cipher/secure_note.rs index 9ddf58f5a..33a654bbd 100644 --- a/crates/bitwarden-core/src/vault/cipher/secure_note.rs +++ b/crates/bitwarden-core/src/vault/cipher/secure_note.rs @@ -1,11 +1,13 @@ -use crate::require; use bitwarden_api_api::models::CipherSecureNoteModel; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema)] #[repr(u8)] diff --git a/crates/bitwarden-core/src/vault/collection.rs b/crates/bitwarden-core/src/vault/collection.rs index e62106934..087b32895 100644 --- a/crates/bitwarden-core/src/vault/collection.rs +++ b/crates/bitwarden-core/src/vault/collection.rs @@ -1,5 +1,4 @@ use bitwarden_api_api::models::CollectionDetailsResponseModel; -use crate::require; use bitwarden_crypto::{ CryptoError, EncString, KeyContainer, KeyDecryptable, LocateKey, SymmetricCryptoKey, }; @@ -7,7 +6,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/vault/domain.rs b/crates/bitwarden-core/src/vault/domain.rs index 79e7be151..dd7ecc7cb 100644 --- a/crates/bitwarden-core/src/vault/domain.rs +++ b/crates/bitwarden-core/src/vault/domain.rs @@ -1,8 +1,10 @@ -use crate::require; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] pub struct GlobalDomains { diff --git a/crates/bitwarden-core/src/vault/folder.rs b/crates/bitwarden-core/src/vault/folder.rs index 32a4faf64..0a11f1a26 100644 --- a/crates/bitwarden-core/src/vault/folder.rs +++ b/crates/bitwarden-core/src/vault/folder.rs @@ -1,4 +1,3 @@ -use crate::require; use bitwarden_api_api::models::FolderResponseModel; use bitwarden_crypto::{ CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, @@ -8,7 +7,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::error::{Error, Result}; +use crate::{ + error::{Error, Result}, + require, +}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase")] diff --git a/crates/bitwarden-core/src/vault/sync.rs b/crates/bitwarden-core/src/vault/sync.rs index cf6c127d2..3c0af948a 100644 --- a/crates/bitwarden-core/src/vault/sync.rs +++ b/crates/bitwarden-core/src/vault/sync.rs @@ -1,7 +1,6 @@ use bitwarden_api_api::models::{ DomainsResponseModel, ProfileOrganizationResponseModel, ProfileResponseModel, SyncResponseModel, }; -use crate::require; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -11,6 +10,7 @@ use crate::{ admin_console::Policy, client::{encryption_settings::EncryptionSettings, Client}, error::{Error, Result}, + require, vault::{Cipher, Collection, Folder}, }; diff --git a/crates/bitwarden-exporters/src/models.rs b/crates/bitwarden-exporters/src/models.rs index 614be9f5e..4e77ad960 100644 --- a/crates/bitwarden-exporters/src/models.rs +++ b/crates/bitwarden-exporters/src/models.rs @@ -243,10 +243,10 @@ impl From for SecureNoteType { #[cfg(test)] mod tests { + use bitwarden_core::vault::{CipherRepromptType, LoginView}; use chrono::{DateTime, Utc}; use super::*; - use bitwarden_core::vault::{CipherRepromptType, LoginView}; #[test] fn test_try_from_folder_view() { From 7a42a36dd56d0f1887d1233c4bce0a5537e4d478 Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 14 Jun 2024 17:34:02 +0200 Subject: [PATCH 09/28] Fix merge issues --- Cargo.lock | 74 +- .../src/platform/client_platform.rs | 2 - .../src/platform/fido2/authenticator.rs | 635 ------------------ .../src/platform/fido2/client.rs | 148 ---- .../src/platform/fido2/crypto.rs | 45 -- .../bitwarden-core/src/platform/fido2/mod.rs | 276 -------- .../src/platform/fido2/traits.rs | 65 -- .../src/platform/fido2/types.rs | 329 --------- crates/bitwarden-core/src/platform/mod.rs | 7 - crates/bitwarden-fido/src/authenticator.rs | 12 +- crates/bitwarden-fido/src/lib.rs | 3 +- crates/bitwarden-send/src/lib.rs | 2 + crates/bitwarden-send/src/send.rs | 4 +- .../src/mobile/client_ciphers.rs | 8 +- crates/bitwarden/Cargo.toml | 1 - 15 files changed, 67 insertions(+), 1544 deletions(-) delete mode 100644 crates/bitwarden-core/src/platform/fido2/authenticator.rs delete mode 100644 crates/bitwarden-core/src/platform/fido2/client.rs delete mode 100644 crates/bitwarden-core/src/platform/fido2/crypto.rs delete mode 100644 crates/bitwarden-core/src/platform/fido2/mod.rs delete mode 100644 crates/bitwarden-core/src/platform/fido2/traits.rs delete mode 100644 crates/bitwarden-core/src/platform/fido2/types.rs diff --git a/Cargo.lock b/Cargo.lock index f8d175edb..dfbba8127 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,8 +357,6 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" name = "bitwarden" version = "0.5.0" dependencies = [ - "async-trait", - "base64 0.21.7", "bitwarden-api-api", "bitwarden-api-identity", "bitwarden-core", @@ -367,27 +365,9 @@ dependencies = [ "bitwarden-fido", "bitwarden-generators", "bitwarden-send", + "bitwarden-sm", "bitwarden-vault", - "chrono", - "getrandom", - "log", - "rand", - "rand_chacha", - "reqwest", - "rustls-platform-verifier", - "schemars", - "security-framework", - "serde", - "serde_json", - "serde_qs", - "serde_repr", "thiserror", - "tokio", - "uniffi", - "uuid", - "wiremock", - "zeroize", - "zxcvbn", ] [[package]] @@ -439,10 +419,37 @@ dependencies = [ name = "bitwarden-core" version = "0.5.0" dependencies = [ + "async-trait", + "base64 0.21.7", + "bitwarden-api-api", + "bitwarden-api-identity", + "bitwarden-crypto", "chrono", + "coset", + "getrandom", + "hmac", + "log", + "p256", + "passkey", + "rand", + "rand_chacha", + "reqwest", + "rustls-platform-verifier", + "schemars", + "security-framework", + "serde", + "serde_json", + "serde_qs", + "serde_repr", + "sha1", + "sha2", "thiserror", + "tokio", "uniffi", "uuid", + "wiremock", + "zeroize", + "zxcvbn", ] [[package]] @@ -486,9 +493,11 @@ dependencies = [ "bitwarden-vault", "chrono", "csv", + "schemars", "serde", "serde_json", "thiserror", + "uniffi", "uuid", ] @@ -518,6 +527,7 @@ dependencies = [ name = "bitwarden-generators" version = "0.5.0" dependencies = [ + "bitwarden-core", "bitwarden-crypto", "rand", "rand_chacha", @@ -584,6 +594,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bitwarden-sm" +version = "0.5.0" +dependencies = [ + "bitwarden-api-api", + "bitwarden-core", + "bitwarden-crypto", + "chrono", + "rand", + "rand_chacha", + "reqwest", + "schemars", + "serde", + "serde_json", + "thiserror", + "tokio", + "uniffi", + "uuid", + "wiremock", +] + [[package]] name = "bitwarden-uniffi" version = "0.1.0" @@ -625,6 +656,7 @@ dependencies = [ "sha1", "sha2", "thiserror", + "tokio", "uniffi", "uuid", ] diff --git a/crates/bitwarden-core/src/platform/client_platform.rs b/crates/bitwarden-core/src/platform/client_platform.rs index 26d0c69f9..1f117d5fe 100644 --- a/crates/bitwarden-core/src/platform/client_platform.rs +++ b/crates/bitwarden-core/src/platform/client_platform.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "uniffi")] -use super::client_fido::ClientFido2; use super::{ generate_fingerprint::{generate_fingerprint, generate_user_fingerprint}, get_user_api_key, FingerprintRequest, FingerprintResponse, SecretVerificationRequest, diff --git a/crates/bitwarden-core/src/platform/fido2/authenticator.rs b/crates/bitwarden-core/src/platform/fido2/authenticator.rs deleted file mode 100644 index 4b643f132..000000000 --- a/crates/bitwarden-core/src/platform/fido2/authenticator.rs +++ /dev/null @@ -1,635 +0,0 @@ -use std::sync::{Arc, Mutex}; - -use bitwarden_core::VaultLocked; -use bitwarden_crypto::{CryptoError, KeyContainer, KeyEncryptable}; -use bitwarden_vault::{CipherError, CipherView, Fido2CredentialView}; -use log::error; -use passkey::{ - authenticator::{Authenticator, DiscoverabilitySupport, StoreInfo, UIHint, UserCheck}, - types::{ - ctap2::{self, Ctap2Error, StatusCode, VendorError}, - Passkey, - }, -}; -use thiserror::Error; - -use super::{ - try_from_credential_new_view, types::*, CheckUserOptions, CheckUserResult, CipherViewContainer, - Fido2CredentialStore, Fido2UserInterface, SelectedCredential, UnknownEnum, AAGUID, -}; -use crate::{ - fill_with_credential, string_to_guid_bytes, try_from_credential_full, Fido2CallbackError, - FillCredentialError, InvalidGuid, -}; - -#[derive(Debug, Error)] -pub enum GetSelectedCredentialError { - #[error("No selected credential available")] - NoSelectedCredential, - #[error("No fido2 credentials found")] - NoCredentialFound, - - #[error(transparent)] - VaultLocked(#[from] VaultLocked), - #[error(transparent)] - CipherError(#[from] CipherError), -} - -#[derive(Debug, Error)] -pub enum MakeCredentialError { - #[error(transparent)] - PublicKeyCredentialParametersError(#[from] PublicKeyCredentialParametersError), - #[error(transparent)] - UnknownEnum(#[from] UnknownEnum), - #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error("Missing attested_credential_data")] - MissingAttestedCredentialData, - #[error("make_credential error: {0}")] - Other(String), -} - -#[derive(Debug, Error)] -pub enum GetAssertionError { - #[error(transparent)] - UnknownEnum(#[from] UnknownEnum), - #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error(transparent)] - GetSelectedCredentialError(#[from] GetSelectedCredentialError), - #[error("Missing attested_credential_data")] - MissingAttestedCredentialData, - #[error("missing user")] - MissingUser, - #[error("get_assertion error: {0}")] - Other(String), -} - -#[derive(Debug, Error)] -pub enum SilentlyDiscoverCredentialsError { - #[error(transparent)] - VaultLocked(#[from] VaultLocked), - #[error(transparent)] - Fido2CallbackError(#[from] Fido2CallbackError), -} - -/// Temporary trait for solving a circular dependency. When moving `Client` to `bitwarden-core` -/// remove this trait. -pub trait FidoEncryptionSettingStore: Send + Sync { - fn get_encryption_settings(&self) -> Result, VaultLocked>; -} - -pub struct Fido2Authenticator<'a> { - pub client: &'a dyn FidoEncryptionSettingStore, - pub user_interface: &'a dyn Fido2UserInterface, - pub credential_store: &'a dyn Fido2CredentialStore, - - pub(crate) selected_cipher: Mutex>, - pub(crate) requested_uv: Mutex>, -} - -impl<'a> Fido2Authenticator<'a> { - pub fn new( - client: &'a dyn FidoEncryptionSettingStore, - user_interface: &'a dyn Fido2UserInterface, - credential_store: &'a dyn Fido2CredentialStore, - ) -> Fido2Authenticator<'a> { - Fido2Authenticator { - client, - user_interface, - credential_store, - selected_cipher: Mutex::new(None), - requested_uv: Mutex::new(None), - } - } - - pub async fn make_credential( - &mut self, - request: MakeCredentialRequest, - ) -> Result { - // Insert the received UV to be able to return it later in check_user - self.requested_uv - .get_mut() - .expect("Mutex is not poisoned") - .replace(request.options.uv); - - let mut authenticator = self.get_authenticator(true); - - let response = authenticator - .make_credential(ctap2::make_credential::Request { - client_data_hash: request.client_data_hash.into(), - rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity { - id: request.rp.id, - name: request.rp.name, - }, - user: passkey::types::webauthn::PublicKeyCredentialUserEntity { - id: request.user.id.into(), - display_name: request.user.display_name, - name: request.user.name, - }, - pub_key_cred_params: request - .pub_key_cred_params - .into_iter() - .map(TryInto::try_into) - .collect::>()?, - exclude_list: request - .exclude_list - .map(|x| x.into_iter().map(TryInto::try_into).collect()) - .transpose()?, - extensions: request - .extensions - .map(|e| serde_json::from_str(&e)) - .transpose()?, - options: passkey::types::ctap2::make_credential::Options { - rk: request.options.rk, - up: true, - uv: self.convert_requested_uv(request.options.uv).await, - }, - pin_auth: None, - pin_protocol: None, - }) - .await; - - let response = match response { - Ok(x) => x, - Err(e) => return Err(MakeCredentialError::Other(format!("{e:?}"))), - }; - - let authenticator_data = response.auth_data.to_vec(); - let attested_credential_data = response - .auth_data - .attested_credential_data - .ok_or(MakeCredentialError::MissingAttestedCredentialData)?; - let credential_id = attested_credential_data.credential_id().to_vec(); - - Ok(MakeCredentialResult { - authenticator_data, - attested_credential_data: attested_credential_data.into_iter().collect(), - credential_id, - }) - } - - pub async fn get_assertion( - &mut self, - request: GetAssertionRequest, - ) -> Result { - // Insert the received UV to be able to return it later in check_user - self.requested_uv - .get_mut() - .expect("Mutex is not poisoned") - .replace(request.options.uv); - - let mut authenticator = self.get_authenticator(false); - - let response = authenticator - .get_assertion(ctap2::get_assertion::Request { - rp_id: request.rp_id, - client_data_hash: request.client_data_hash.into(), - allow_list: request - .allow_list - .map(|l| { - l.into_iter() - .map(TryInto::try_into) - .collect::, _>>() - }) - .transpose()?, - extensions: request - .extensions - .map(|e| serde_json::from_str(&e)) - .transpose()?, - options: passkey::types::ctap2::make_credential::Options { - rk: request.options.rk, - up: true, - uv: self.convert_requested_uv(request.options.uv).await, - }, - pin_auth: None, - pin_protocol: None, - }) - .await; - - let response = match response { - Ok(x) => x, - Err(e) => return Err(GetAssertionError::Other(format!("{e:?}"))), - }; - - let authenticator_data = response.auth_data.to_vec(); - let credential_id = response - .auth_data - .attested_credential_data - .ok_or(GetAssertionError::MissingAttestedCredentialData)? - .credential_id() - .to_vec(); - - Ok(GetAssertionResult { - credential_id, - authenticator_data, - signature: response.signature.into(), - user_handle: response - .user - .ok_or(GetAssertionError::MissingUser)? - .id - .into(), - selected_credential: self.get_selected_credential()?, - }) - } - - pub async fn silently_discover_credentials( - &mut self, - rp_id: String, - ) -> Result, SilentlyDiscoverCredentialsError> { - let enc = self.client.internal.get_encryption_settings()?; - let result = self.credential_store.find_credentials(None, rp_id).await?; - - Ok(result - .into_iter() - .flat_map(|c| c.decrypt_fido2_credentials(&*enc)) - .flatten() - .collect()) - } - - pub(super) fn get_authenticator( - &self, - create_credential: bool, - ) -> Authenticator { - Authenticator::new( - AAGUID, - CredentialStoreImpl { - authenticator: self, - create_credential, - }, - UserValidationMethodImpl { - authenticator: self, - }, - ) - } - - async fn convert_requested_uv(&self, uv: UV) -> bool { - let verification_enabled = self.user_interface.is_verification_enabled().await; - match (uv, verification_enabled) { - (UV::Preferred, true) => true, - (UV::Preferred, false) => false, - (UV::Required, _) => true, - (UV::Discouraged, _) => false, - } - } - - pub(super) fn get_selected_credential( - &self, - ) -> Result { - let enc = self.client.internal.get_encryption_settings()?; - - let cipher = self - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .clone() - .ok_or(GetSelectedCredentialError::NoSelectedCredential)?; - - let creds = cipher.decrypt_fido2_credentials(&*enc)?; - - let credential = creds - .first() - .ok_or(GetSelectedCredentialError::NoCredentialFound)? - .clone(); - - Ok(SelectedCredential { cipher, credential }) - } -} - -pub(super) struct CredentialStoreImpl<'a> { - authenticator: &'a Fido2Authenticator<'a>, - create_credential: bool, -} -pub(super) struct UserValidationMethodImpl<'a> { - authenticator: &'a Fido2Authenticator<'a>, -} - -#[async_trait::async_trait] -impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { - type PasskeyItem = CipherViewContainer; - async fn find_credentials( - &self, - ids: Option<&[passkey::types::webauthn::PublicKeyCredentialDescriptor]>, - rp_id: &str, - ) -> Result, StatusCode> { - #[derive(Debug, Error)] - enum InnerError { - #[error(transparent)] - VaultLocked(#[from] VaultLocked), - #[error(transparent)] - CipherError(#[from] CipherError), - #[error(transparent)] - CryptoError(#[from] CryptoError), - #[error(transparent)] - Fido2CallbackError(#[from] Fido2CallbackError), - } - - // This is just a wrapper around the actual implementation to allow for ? error handling - async fn inner( - this: &CredentialStoreImpl<'_>, - ids: Option<&[passkey::types::webauthn::PublicKeyCredentialDescriptor]>, - rp_id: &str, - ) -> Result, InnerError> { - let ids: Option>> = - ids.map(|ids| ids.iter().map(|id| id.id.clone().into()).collect()); - - let ciphers = this - .authenticator - .credential_store - .find_credentials(ids, rp_id.to_string()) - .await?; - - let enc = this - .authenticator - .client - .internal - .get_encryption_settings()?; - - // Remove any that don't have Fido2 credentials - let creds: Vec<_> = ciphers - .into_iter() - .filter(|c| { - c.login - .as_ref() - .and_then(|l| l.fido2_credentials.as_ref()) - .is_some() - }) - .collect(); - - // When using the credential for authentication we have to ask the user to pick one. - if this.create_credential { - Ok(creds - .into_iter() - .map(|c| CipherViewContainer::new(c, &*enc)) - .collect::>()?) - } else { - let picked = this - .authenticator - .user_interface - .pick_credential_for_authentication(creds) - .await?; - - // Store the selected credential for later use - this.authenticator - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .replace(picked.clone()); - - Ok(vec![CipherViewContainer::new(picked, &*enc)?]) - } - } - - inner(self, ids, rp_id).await.map_err(|e| { - error!("Error finding credentials: {e:?}"); - VendorError::try_from(0xF0) - .expect("Valid vendor error code") - .into() - }) - } - - async fn save_credential( - &mut self, - cred: Passkey, - user: passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, - rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, - _options: passkey::types::ctap2::get_assertion::Options, - ) -> Result<(), StatusCode> { - #[derive(Debug, Error)] - enum InnerError { - #[error(transparent)] - VaultLocked(#[from] VaultLocked), - #[error(transparent)] - FillCredentialError(#[from] FillCredentialError), - #[error(transparent)] - CipherError(#[from] CipherError), - #[error(transparent)] - CryptoError(#[from] CryptoError), - #[error(transparent)] - Fido2CallbackError(#[from] Fido2CallbackError), - - #[error("No selected credential available")] - NoSelectedCredential, - } - - // This is just a wrapper around the actual implementation to allow for ? error handling - async fn inner( - this: &mut CredentialStoreImpl<'_>, - cred: Passkey, - user: passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, - rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, - ) -> Result<(), InnerError> { - let enc = this - .authenticator - .client - .internal - .get_encryption_settings()?; - - let cred = try_from_credential_full(cred, user, rp)?; - - // Get the previously selected cipher and add the new credential to it - let mut selected: CipherView = this - .authenticator - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .clone() - .ok_or(InnerError::NoSelectedCredential)?; - - selected.set_new_fido2_credentials(&*enc, vec![cred])?; - - // Store the updated credential for later use - this.authenticator - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .replace(selected.clone()); - - // Encrypt the updated cipher before sending it to the clients to be stored - let key = enc.get_key(&selected.organization_id).ok_or(VaultLocked)?; - let encrypted = selected.encrypt_with_key(key)?; - - this.authenticator - .credential_store - .save_credential(encrypted) - .await?; - - Ok(()) - } - - inner(self, cred, user, rp).await.map_err(|e| { - error!("Error saving credential: {e:?}"); - VendorError::try_from(0xF1) - .expect("Valid vendor error code") - .into() - }) - } - - async fn update_credential(&mut self, cred: Passkey) -> Result<(), StatusCode> { - #[derive(Debug, Error)] - enum InnerError { - #[error(transparent)] - VaultLocked(#[from] VaultLocked), - #[error(transparent)] - InvalidGuid(#[from] InvalidGuid), - #[error("Credential ID does not match selected credential")] - CredentialIdMismatch, - #[error(transparent)] - FillCredentialError(#[from] FillCredentialError), - #[error(transparent)] - CipherError(#[from] CipherError), - #[error(transparent)] - CryptoError(#[from] CryptoError), - #[error(transparent)] - Fido2CallbackError(#[from] Fido2CallbackError), - #[error(transparent)] - GetSelectedCredentialError(#[from] GetSelectedCredentialError), - } - - // This is just a wrapper around the actual implementation to allow for ? error handling - async fn inner( - this: &mut CredentialStoreImpl<'_>, - cred: Passkey, - ) -> Result<(), InnerError> { - let enc = this - .authenticator - .client - .internal - .get_encryption_settings()?; - - // Get the previously selected cipher and update the credential - let selected = this.authenticator.get_selected_credential()?; - - // Check that the provided credential ID matches the selected credential - let new_id: &Vec = &cred.credential_id; - let selected_id = string_to_guid_bytes(&selected.credential.credential_id)?; - if new_id != &selected_id { - return Err(InnerError::CredentialIdMismatch); - } - - let cred = fill_with_credential(&selected.credential, cred)?; - - let mut selected = selected.cipher; - selected.set_new_fido2_credentials(&*enc, vec![cred])?; - - // Store the updated credential for later use - this.authenticator - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .replace(selected.clone()); - - // Encrypt the updated cipher before sending it to the clients to be stored - let key = enc.get_key(&selected.organization_id).ok_or(VaultLocked)?; - let encrypted = selected.encrypt_with_key(key)?; - - this.authenticator - .credential_store - .save_credential(encrypted) - .await?; - - Ok(()) - } - - inner(self, cred).await.map_err(|e| { - error!("Error updating credential: {e:?}"); - VendorError::try_from(0xF2) - .expect("Valid vendor error code") - .into() - }) - } - - async fn get_info(&self) -> StoreInfo { - StoreInfo { - discoverability: DiscoverabilitySupport::Full, - } - } -} - -#[async_trait::async_trait] -impl passkey::authenticator::UserValidationMethod for UserValidationMethodImpl<'_> { - type PasskeyItem = CipherViewContainer; - - async fn check_user<'a>( - &self, - hint: UIHint<'a, Self::PasskeyItem>, - presence: bool, - _verification: bool, - ) -> Result { - let verification = self - .authenticator - .requested_uv - .lock() - .expect("Mutex is not poisoned") - .ok_or(Ctap2Error::UserVerificationInvalid)?; - - let options = CheckUserOptions { - require_presence: presence, - require_verification: verification.into(), - }; - - let result = match hint { - UIHint::RequestNewCredential(user, rp) => { - let new_credential = try_from_credential_new_view(user, rp) - .map_err(|_| Ctap2Error::InvalidCredential)?; - - let cipher_view = self - .authenticator - .user_interface - .check_user_and_pick_credential_for_creation(options, new_credential) - .await - .map_err(|_| Ctap2Error::OperationDenied)?; - - self.authenticator - .selected_cipher - .lock() - .expect("Mutex is not poisoned") - .replace(cipher_view); - - Ok(CheckUserResult { - user_present: true, - user_verified: verification != UV::Discouraged, - }) - } - _ => { - self.authenticator - .user_interface - .check_user(options, map_ui_hint(hint)) - .await - } - }; - - let result = result.map_err(|e| { - error!("Error checking user: {e:?}"); - Ctap2Error::UserVerificationInvalid - })?; - - Ok(UserCheck { - presence: result.user_present, - verification: result.user_verified, - }) - } - - async fn is_presence_enabled(&self) -> bool { - true - } - - async fn is_verification_enabled(&self) -> Option { - Some( - self.authenticator - .user_interface - .is_verification_enabled() - .await, - ) - } -} - -fn map_ui_hint(hint: UIHint<'_, CipherViewContainer>) -> UIHint<'_, CipherView> { - use UIHint::*; - match hint { - InformExcludedCredentialFound(c) => InformExcludedCredentialFound(&c.cipher), - InformNoCredentialsFound => InformNoCredentialsFound, - RequestNewCredential(u, r) => RequestNewCredential(u, r), - RequestExistingCredential(c) => RequestExistingCredential(&c.cipher), - } -} diff --git a/crates/bitwarden-core/src/platform/fido2/client.rs b/crates/bitwarden-core/src/platform/fido2/client.rs deleted file mode 100644 index a72dae6f5..000000000 --- a/crates/bitwarden-core/src/platform/fido2/client.rs +++ /dev/null @@ -1,148 +0,0 @@ -use passkey::client::WebauthnError; -use reqwest::Url; -use thiserror::Error; - -use super::{ - authenticator::GetSelectedCredentialError, - get_string_name_from_enum, - types::{ - AuthenticatorAssertionResponse, AuthenticatorAttestationResponse, ClientData, - ClientExtensionResults, CredPropsResult, - }, - Fido2Authenticator, PublicKeyCredentialAuthenticatorAssertionResponse, - PublicKeyCredentialAuthenticatorAttestationResponse, -}; - -#[derive(Debug, Error)] -#[error("Invalid origin: {0}")] -pub struct InvalidOriginError(String); - -#[derive(Debug, Error)] -pub enum Fido2ClientError { - #[error(transparent)] - InvalidOrigin(#[from] InvalidOriginError), - #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error(transparent)] - GetSelectedCredentialError(#[from] GetSelectedCredentialError), - - #[error("Webauthn error: {0:?}")] - Webauthn(WebauthnError), -} - -impl From for Fido2ClientError { - fn from(e: WebauthnError) -> Self { - Self::Webauthn(e) - } -} - -pub struct Fido2Client<'a> { - pub authenticator: Fido2Authenticator<'a>, -} - -impl<'a> Fido2Client<'a> { - pub async fn register( - &mut self, - origin: String, - request: String, - client_data: ClientData, - ) -> Result { - let origin = Url::parse(&origin).map_err(|e| InvalidOriginError(format!("{}", e)))?; - - let request: passkey::types::webauthn::CredentialCreationOptions = - serde_json::from_str(&request)?; - - // Insert the received UV to be able to return it later in check_user - let uv = request - .public_key - .authenticator_selection - .as_ref() - .map(|s| s.user_verification.into()); - *self - .authenticator - .requested_uv - .get_mut() - .expect("Mutex is not poisoned") = uv; - - let rp_id = request.public_key.rp.id.clone(); - - let mut client = passkey::client::Client::new(self.authenticator.get_authenticator(true)); - let result = client.register(&origin, request, client_data).await?; - - Ok(PublicKeyCredentialAuthenticatorAttestationResponse { - id: result.id, - raw_id: result.raw_id.into(), - ty: get_string_name_from_enum(result.ty)?, - authenticator_attachment: result - .authenticator_attachment - .map(get_string_name_from_enum) - .transpose()?, - client_extension_results: ClientExtensionResults { - cred_props: result.client_extension_results.cred_props.map(Into::into), - }, - response: AuthenticatorAttestationResponse { - client_data_json: result.response.client_data_json.into(), - authenticator_data: result.response.authenticator_data.into(), - public_key: result.response.public_key.map(|x| x.into()), - public_key_algorithm: result.response.public_key_algorithm, - attestation_object: result.response.attestation_object.into(), - transports: if rp_id.unwrap_or_default() == "https://google.com" { - Some(vec!["internal".to_string(), "usb".to_string()]) - } else { - Some(vec!["internal".to_string()]) - }, - }, - selected_credential: self.authenticator.get_selected_credential()?, - }) - } - - pub async fn authenticate( - &mut self, - origin: String, - request: String, - client_data: ClientData, - ) -> Result { - let origin = Url::parse(&origin).map_err(|e| InvalidOriginError(format!("{}", e)))?; - - let request: passkey::types::webauthn::CredentialRequestOptions = - serde_json::from_str(&request)?; - - // Insert the received UV to be able to return it later in check_user - let uv = request.public_key.user_verification.into(); - self.authenticator - .requested_uv - .get_mut() - .expect("Mutex is not poisoned") - .replace(uv); - - let mut client = passkey::client::Client::new(self.authenticator.get_authenticator(false)); - let result = client.authenticate(&origin, request, client_data).await?; - - Ok(PublicKeyCredentialAuthenticatorAssertionResponse { - id: result.id, - raw_id: result.raw_id.into(), - ty: get_string_name_from_enum(result.ty)?, - - authenticator_attachment: result - .authenticator_attachment - .map(get_string_name_from_enum) - .transpose()?, - client_extension_results: ClientExtensionResults { - cred_props: result - .client_extension_results - .cred_props - .map(|c| CredPropsResult { - rk: c.discoverable, - authenticator_display_name: c.authenticator_display_name, - }), - }, - response: AuthenticatorAssertionResponse { - client_data_json: result.response.client_data_json.into(), - authenticator_data: result.response.authenticator_data.into(), - signature: result.response.signature.into(), - user_handle: result.response.user_handle.unwrap_or_default().into(), - }, - selected_credential: self.authenticator.get_selected_credential()?, - }) - } -} diff --git a/crates/bitwarden-core/src/platform/fido2/crypto.rs b/crates/bitwarden-core/src/platform/fido2/crypto.rs deleted file mode 100644 index 8c72b5341..000000000 --- a/crates/bitwarden-core/src/platform/fido2/crypto.rs +++ /dev/null @@ -1,45 +0,0 @@ -use coset::{iana, CoseKey}; -use p256::{pkcs8::EncodePrivateKey, SecretKey}; -use passkey::authenticator::{private_key_from_cose_key, CoseKeyPair}; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum CoseKeyToPkcs8Error { - #[error("Failed to extract private key from cose_key")] - FailedToExtractPrivateKeyFromCoseKey, - #[error("Failed to convert P256 private key to PKC8")] - FailedToConvertP256PrivateKeyToPkcs8, -} - -pub(crate) fn cose_key_to_pkcs8(cose_key: &CoseKey) -> Result, CoseKeyToPkcs8Error> { - // cose_key. - let secret_key = private_key_from_cose_key(cose_key).map_err(|error| { - log::error!("Failed to extract private key from cose_key: {:?}", error); - CoseKeyToPkcs8Error::FailedToExtractPrivateKeyFromCoseKey - })?; - - let vec = secret_key - .to_pkcs8_der() - .map_err(|error| { - log::error!("Failed to convert P256 private key to PKC8: {:?}", error); - CoseKeyToPkcs8Error::FailedToConvertP256PrivateKeyToPkcs8 - })? - .as_bytes() - .to_vec(); - - Ok(vec) -} - -#[derive(Debug, Error)] -#[error("Failed to extract private key from secret_key")] -pub struct PrivateKeyFromSecretKeyError; - -pub fn pkcs8_to_cose_key(secret_key: &[u8]) -> Result { - let secret_key = SecretKey::from_slice(secret_key).map_err(|error| { - log::error!("Failed to extract private key from secret_key: {:?}", error); - PrivateKeyFromSecretKeyError - })?; - - let cose_key_pair = CoseKeyPair::from_secret_key(&secret_key, iana::Algorithm::ES256); - Ok(cose_key_pair.private) -} diff --git a/crates/bitwarden-core/src/platform/fido2/mod.rs b/crates/bitwarden-core/src/platform/fido2/mod.rs deleted file mode 100644 index f3532a3c8..000000000 --- a/crates/bitwarden-core/src/platform/fido2/mod.rs +++ /dev/null @@ -1,276 +0,0 @@ -use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; -use bitwarden_crypto::KeyContainer; -use bitwarden_vault::{ - CipherError, CipherView, Fido2CredentialFullView, Fido2CredentialNewView, Fido2CredentialView, -}; -use crypto::{CoseKeyToPkcs8Error, PrivateKeyFromSecretKeyError}; -use passkey::types::{ctap2::Aaguid, Passkey}; - -#[cfg(feature = "uniffi")] -uniffi::setup_scaffolding!(); - -mod authenticator; -mod client; -mod crypto; -mod traits; -mod types; -pub use authenticator::{ - Fido2Authenticator, FidoEncryptionSettingStore, GetAssertionError, MakeCredentialError, - SilentlyDiscoverCredentialsError, -}; -pub use client::{Fido2Client, Fido2ClientError}; -pub use passkey::authenticator::UIHint; -use thiserror::Error; -pub use traits::{ - CheckUserOptions, CheckUserResult, Fido2CallbackError, Fido2CredentialStore, - Fido2UserInterface, Verification, -}; -pub use types::{ - AuthenticatorAssertionResponse, AuthenticatorAttestationResponse, ClientData, - GetAssertionRequest, GetAssertionResult, MakeCredentialRequest, MakeCredentialResult, Options, - PublicKeyCredentialAuthenticatorAssertionResponse, - PublicKeyCredentialAuthenticatorAttestationResponse, PublicKeyCredentialRpEntity, - PublicKeyCredentialUserEntity, -}; - -use self::crypto::{cose_key_to_pkcs8, pkcs8_to_cose_key}; - -// This is the AAGUID for the Bitwarden Passkey provider (d548826e-79b4-db40-a3d8-11116f7e8349) -// It is used for the Relaying Parties to identify the authenticator during registration -const AAGUID: Aaguid = Aaguid([ - 0xd5, 0x48, 0x82, 0x6e, 0x79, 0xb4, 0xdb, 0x40, 0xa3, 0xd8, 0x11, 0x11, 0x6f, 0x7e, 0x83, 0x49, -]); - -#[allow(dead_code)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct SelectedCredential { - cipher: CipherView, - credential: Fido2CredentialView, -} - -// This container is needed so we can properly implement the TryFrom trait for Passkey -// Otherwise we need to decrypt the Fido2 credentials every time we create a CipherView -#[derive(Clone)] -pub(crate) struct CipherViewContainer { - cipher: CipherView, - fido2_credentials: Vec, -} - -impl CipherViewContainer { - fn new(cipher: CipherView, enc: &dyn KeyContainer) -> Result { - let fido2_credentials = cipher.get_fido2_credentials(enc)?; - Ok(Self { - cipher, - fido2_credentials, - }) - } -} - -#[derive(Debug, Error)] -pub enum Fido2Error { - #[error(transparent)] - UnknownEnum(#[from] UnknownEnum), - - #[error(transparent)] - InvalidGuid(#[from] InvalidGuid), - - #[error(transparent)] - PrivateKeyFromSecretKeyError(#[from] PrivateKeyFromSecretKeyError), - - #[error("No Fido2 credentials found")] - NoFido2CredentialsFound, -} - -impl TryFrom for Passkey { - type Error = Fido2Error; - - fn try_from(value: CipherViewContainer) -> Result { - let cred = value - .fido2_credentials - .first() - .ok_or(Fido2Error::NoFido2CredentialsFound)?; - - try_from_credential_full_view(cred.clone()) - } -} - -fn try_from_credential_full_view(value: Fido2CredentialFullView) -> Result { - let counter: u32 = value.counter.parse().expect("Invalid counter"); - let counter = (counter != 0).then_some(counter); - - let key = pkcs8_to_cose_key(&value.key_value)?; - - Ok(Passkey { - key, - credential_id: string_to_guid_bytes(&value.credential_id)?.into(), - rp_id: value.rp_id.clone(), - user_handle: value.user_handle.map(|u| u.into()), - counter, - }) -} - -#[derive(Debug, Error)] -pub enum FillCredentialError { - #[error(transparent)] - InvalidInputLength(#[from] InvalidInputLength), - #[error(transparent)] - CoseKeyToPkcs8Error(#[from] CoseKeyToPkcs8Error), -} - -pub fn fill_with_credential( - view: &Fido2CredentialView, - value: Passkey, -) -> Result { - let cred_id: Vec = value.credential_id.into(); - - Ok(Fido2CredentialFullView { - credential_id: guid_bytes_to_string(&cred_id)?, - key_type: "public-key".to_owned(), - key_algorithm: "ECDSA".to_owned(), - key_curve: "P-256".to_owned(), - key_value: cose_key_to_pkcs8(&value.key)?, - rp_id: value.rp_id, - rp_name: view.rp_name.clone(), - user_handle: Some(cred_id), - - counter: value.counter.unwrap_or(0).to_string(), - user_name: view.user_name.clone(), - user_display_name: view.user_display_name.clone(), - discoverable: "true".to_owned(), - creation_date: chrono::offset::Utc::now(), - }) -} - -pub(crate) fn try_from_credential_new_view( - user: &passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, - rp: &passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, -) -> Result { - let cred_id: Vec = vec![0; 16]; - - Ok(Fido2CredentialNewView { - credential_id: guid_bytes_to_string(&cred_id)?, - key_type: "public-key".to_owned(), - key_algorithm: "ECDSA".to_owned(), - key_curve: "P-256".to_owned(), - rp_id: rp.id.clone(), - rp_name: rp.name.clone(), - user_handle: Some(cred_id), - - counter: 0.to_string(), - user_name: user.name.clone(), - user_display_name: user.display_name.clone(), - discoverable: "true".to_owned(), - creation_date: chrono::offset::Utc::now(), - }) -} - -pub(crate) fn try_from_credential_full( - value: Passkey, - user: passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, - rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, -) -> Result { - let cred_id: Vec = value.credential_id.into(); - - Ok(Fido2CredentialFullView { - credential_id: guid_bytes_to_string(&cred_id)?, - key_type: "public-key".to_owned(), - key_algorithm: "ECDSA".to_owned(), - key_curve: "P-256".to_owned(), - key_value: cose_key_to_pkcs8(&value.key)?, - rp_id: value.rp_id, - rp_name: rp.name, - user_handle: Some(cred_id), - - counter: value.counter.unwrap_or(0).to_string(), - user_name: user.name, - user_display_name: user.display_name, - discoverable: "true".to_owned(), - creation_date: chrono::offset::Utc::now(), - }) -} - -#[derive(Debug, Error)] -#[error("Input should be a 16 byte array")] -pub struct InvalidInputLength; - -pub fn guid_bytes_to_string(source: &[u8]) -> Result { - if source.len() != 16 { - return Err(InvalidInputLength); - } - Ok(uuid::Uuid::from_bytes(source.try_into().expect("Invalid length")).to_string()) -} - -#[derive(Debug, Error)] -#[error("Invalid GUID")] -pub struct InvalidGuid; - -pub fn string_to_guid_bytes(source: &str) -> Result, InvalidGuid> { - if source.starts_with("b64.") { - let bytes = URL_SAFE_NO_PAD - .decode(source.trim_start_matches("b64.")) - .map_err(|_| InvalidGuid)?; - Ok(bytes) - } else { - let Ok(uuid) = uuid::Uuid::try_parse(source) else { - return Err(InvalidGuid); - }; - Ok(uuid.as_bytes().to_vec()) - } -} - -#[derive(Debug, Error)] -#[error("Unknown enum value")] -pub struct UnknownEnum; - -// Some utilities to convert back and forth between enums and strings -fn get_enum_from_string_name(s: &str) -> Result { - let serialized = format!(r#""{}""#, s); - let deserialized: T = serde_json::from_str(&serialized).map_err(|_| UnknownEnum)?; - Ok(deserialized) -} - -fn get_string_name_from_enum(s: impl serde::Serialize) -> Result { - let serialized = serde_json::to_string(&s)?; - let deserialized: String = serde_json::from_str(&serialized)?; - Ok(deserialized) -} - -#[cfg(test)] -mod tests { - use passkey::types::webauthn::AuthenticatorAttachment; - - use super::{get_enum_from_string_name, get_string_name_from_enum}; - - #[test] - fn test_enum_string_conversion_works_as_expected() { - assert_eq!( - get_string_name_from_enum(AuthenticatorAttachment::CrossPlatform).unwrap(), - "cross-platform" - ); - - assert_eq!( - get_enum_from_string_name::("cross-platform").unwrap(), - AuthenticatorAttachment::CrossPlatform - ); - } - - #[test] - fn string_to_guid_with_uuid_works() { - let uuid = "d548826e-79b4-db40-a3d8-11116f7e8349"; - let bytes = super::string_to_guid_bytes(uuid).unwrap(); - assert_eq!( - bytes, - vec![213, 72, 130, 110, 121, 180, 219, 64, 163, 216, 17, 17, 111, 126, 131, 73] - ); - } - - #[test] - fn string_to_guid_with_b64_works() { - let b64 = "b64.1UiCbnm020Cj2BERb36DSQ"; - let bytes = super::string_to_guid_bytes(b64).unwrap(); - assert_eq!( - bytes, - vec![213, 72, 130, 110, 121, 180, 219, 64, 163, 216, 17, 17, 111, 126, 131, 73] - ); - } -} diff --git a/crates/bitwarden-core/src/platform/fido2/traits.rs b/crates/bitwarden-core/src/platform/fido2/traits.rs deleted file mode 100644 index 0769eeb2a..000000000 --- a/crates/bitwarden-core/src/platform/fido2/traits.rs +++ /dev/null @@ -1,65 +0,0 @@ -use bitwarden_vault::{Cipher, CipherView, Fido2CredentialNewView}; -use passkey::authenticator::UIHint; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum Fido2CallbackError { - #[error("The operation requires user interaction")] - UserInterfaceRequired, - - #[error("The operation was cancelled by the user")] - OperationCancelled, - - #[error("Unknown error: {0}")] - Unknown(String), -} - -#[async_trait::async_trait] -pub trait Fido2UserInterface: Send + Sync { - async fn check_user<'a>( - &self, - options: CheckUserOptions, - hint: UIHint<'a, CipherView>, - ) -> Result; - async fn pick_credential_for_authentication( - &self, - available_credentials: Vec, - ) -> Result; - async fn check_user_and_pick_credential_for_creation( - &self, - options: CheckUserOptions, - new_credential: Fido2CredentialNewView, - ) -> Result; - async fn is_verification_enabled(&self) -> bool; -} - -#[async_trait::async_trait] -pub trait Fido2CredentialStore: Send + Sync { - async fn find_credentials( - &self, - ids: Option>>, - rip_id: String, - ) -> Result, Fido2CallbackError>; - - async fn save_credential(&self, cred: Cipher) -> Result<(), Fido2CallbackError>; -} - -#[derive(Clone)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct CheckUserOptions { - pub require_presence: bool, - pub require_verification: Verification, -} - -#[derive(Clone)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] -pub enum Verification { - Discouraged, - Preferred, - Required, -} - -pub struct CheckUserResult { - pub user_present: bool, - pub user_verified: bool, -} diff --git a/crates/bitwarden-core/src/platform/fido2/types.rs b/crates/bitwarden-core/src/platform/fido2/types.rs deleted file mode 100644 index 16edde6ea..000000000 --- a/crates/bitwarden-core/src/platform/fido2/types.rs +++ /dev/null @@ -1,329 +0,0 @@ -use passkey::types::webauthn::UserVerificationRequirement; -use serde::Serialize; -use thiserror::Error; - -use super::{get_enum_from_string_name, SelectedCredential, UnknownEnum, Verification}; - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialRpEntity { - pub id: String, - pub name: Option, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialUserEntity { - pub id: Vec, - pub display_name: String, - pub name: String, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialParameters { - pub ty: String, - pub alg: i64, -} - -#[derive(Debug, Error)] -pub enum PublicKeyCredentialParametersError { - #[error("Invalid algorithm")] - InvalidAlgorithm, - - #[error("Unknown type")] - UnknownEnum(#[from] UnknownEnum), -} - -impl TryFrom - for passkey::types::webauthn::PublicKeyCredentialParameters -{ - type Error = PublicKeyCredentialParametersError; - - fn try_from(value: PublicKeyCredentialParameters) -> Result { - use coset::iana::EnumI64; - Ok(Self { - ty: get_enum_from_string_name(&value.ty)?, - alg: coset::iana::Algorithm::from_i64(value.alg) - .ok_or(PublicKeyCredentialParametersError::InvalidAlgorithm)?, - }) - } -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialDescriptor { - pub ty: String, - pub id: Vec, - pub transports: Option>, -} - -impl TryFrom - for passkey::types::webauthn::PublicKeyCredentialDescriptor -{ - type Error = UnknownEnum; - - fn try_from(value: PublicKeyCredentialDescriptor) -> Result { - Ok(Self { - ty: get_enum_from_string_name(&value.ty)?, - id: value.id.into(), - transports: value - .transports - .map(|tt| { - tt.into_iter() - .map(|t| get_enum_from_string_name(&t)) - .collect::, Self::Error>>() - }) - .transpose()?, - }) - } -} - -pub type Extensions = Option; - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct MakeCredentialRequest { - pub client_data_hash: Vec, - pub rp: PublicKeyCredentialRpEntity, - pub user: PublicKeyCredentialUserEntity, - pub pub_key_cred_params: Vec, - pub exclude_list: Option>, - pub options: Options, - pub extensions: Extensions, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct MakeCredentialResult { - pub authenticator_data: Vec, - pub attested_credential_data: Vec, - pub credential_id: Vec, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct GetAssertionRequest { - pub rp_id: String, - pub client_data_hash: Vec, - pub allow_list: Option>, - pub options: Options, - pub extensions: Extensions, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct Options { - pub rk: bool, - pub uv: UV, -} - -impl From for Options { - fn from(value: super::CheckUserOptions) -> Self { - Self { - rk: value.require_presence, - uv: value.require_verification.into(), - } - } -} - -impl From for super::CheckUserOptions { - fn from(value: Options) -> Self { - Self { - require_presence: value.rk, - require_verification: value.uv.into(), - } - } -} - -#[derive(Eq, PartialEq, Clone, Copy)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] -pub enum UV { - Discouraged, - Preferred, - Required, -} - -impl From for Verification { - fn from(value: UV) -> Self { - match value { - UV::Discouraged => Verification::Discouraged, - UV::Preferred => Verification::Preferred, - UV::Required => Verification::Required, - } - } -} - -impl From for UV { - fn from(value: Verification) -> Self { - match value { - Verification::Discouraged => UV::Discouraged, - Verification::Preferred => UV::Preferred, - Verification::Required => UV::Required, - } - } -} - -impl From for UV { - fn from(value: UserVerificationRequirement) -> Self { - match value { - UserVerificationRequirement::Discouraged => UV::Discouraged, - UserVerificationRequirement::Preferred => UV::Preferred, - UserVerificationRequirement::Required => UV::Required, - } - } -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct GetAssertionResult { - pub credential_id: Vec, - pub authenticator_data: Vec, - pub signature: Vec, - pub user_handle: Vec, - - pub selected_credential: SelectedCredential, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] -pub enum ClientData { - DefaultWithExtraData { android_package_name: String }, - DefaultWithCustomHash { hash: Vec }, -} - -#[derive(Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub(super) struct AndroidClientData { - android_package_name: String, -} - -impl passkey::client::ClientData> for ClientData { - fn extra_client_data(&self) -> Option { - match self { - ClientData::DefaultWithExtraData { - android_package_name, - } => Some(AndroidClientData { - android_package_name: android_package_name.clone(), - }), - ClientData::DefaultWithCustomHash { .. } => None, - } - } - - fn client_data_hash(&self) -> Option> { - match self { - ClientData::DefaultWithExtraData { .. } => None, - ClientData::DefaultWithCustomHash { hash } => Some(hash.clone()), - } - } -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct ClientExtensionResults { - pub cred_props: Option, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct CredPropsResult { - pub rk: Option, - pub authenticator_display_name: Option, -} - -impl From for CredPropsResult { - fn from(value: passkey::types::webauthn::CredentialPropertiesOutput) -> Self { - Self { - rk: value.discoverable, - authenticator_display_name: value.authenticator_display_name, - } - } -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialAuthenticatorAttestationResponse { - pub id: String, - pub raw_id: Vec, - pub ty: String, - pub authenticator_attachment: Option, - pub client_extension_results: ClientExtensionResults, - pub response: AuthenticatorAttestationResponse, - pub selected_credential: SelectedCredential, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct AuthenticatorAttestationResponse { - pub client_data_json: Vec, - pub authenticator_data: Vec, - pub public_key: Option>, - pub public_key_algorithm: i64, - pub attestation_object: Vec, - pub transports: Option>, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct PublicKeyCredentialAuthenticatorAssertionResponse { - pub id: String, - pub raw_id: Vec, - pub ty: String, - pub authenticator_attachment: Option, - pub client_extension_results: ClientExtensionResults, - pub response: AuthenticatorAssertionResponse, - pub selected_credential: SelectedCredential, -} - -#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] -pub struct AuthenticatorAssertionResponse { - pub client_data_json: Vec, - pub authenticator_data: Vec, - pub signature: Vec, - pub user_handle: Vec, -} - -#[cfg(test)] -mod tests { - use serde::{Deserialize, Serialize}; - - use super::AndroidClientData; - - // This is a stripped down of the passkey-rs implementation, to test the - // serialization of the `ClientData` enum, and to make sure that () and None - // are serialized the same way when going through #[serde(flatten)]. - #[derive(Serialize, Deserialize)] - #[serde(rename_all = "camelCase")] - pub struct CollectedClientData - where - E: Serialize, - { - pub origin: String, - - #[serde(flatten)] - pub extra_data: E, - } - - #[test] - fn test_serialize_unit_data() { - let data = CollectedClientData { - origin: "https://example.com".to_owned(), - extra_data: (), - }; - - let serialized = serde_json::to_string(&data).unwrap(); - assert_eq!(serialized, r#"{"origin":"https://example.com"}"#); - } - - #[test] - fn test_serialize_none_data() { - let data = CollectedClientData { - origin: "https://example.com".to_owned(), - extra_data: Option::::None, - }; - - let serialized = serde_json::to_string(&data).unwrap(); - assert_eq!(serialized, r#"{"origin":"https://example.com"}"#); - } - - #[test] - fn test_serialize_android_data() { - let data = CollectedClientData { - origin: "https://example.com".to_owned(), - extra_data: Some(AndroidClientData { - android_package_name: "com.example.app".to_owned(), - }), - }; - - let serialized = serde_json::to_string(&data).unwrap(); - assert_eq!( - serialized, - r#"{"origin":"https://example.com","androidPackageName":"com.example.app"}"# - ); - } -} diff --git a/crates/bitwarden-core/src/platform/mod.rs b/crates/bitwarden-core/src/platform/mod.rs index 0fc051ac3..031554be0 100644 --- a/crates/bitwarden-core/src/platform/mod.rs +++ b/crates/bitwarden-core/src/platform/mod.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "uniffi")] -pub mod client_fido; pub mod client_platform; mod generate_fingerprint; mod get_user_api_key; @@ -9,8 +7,3 @@ pub use generate_fingerprint::{FingerprintRequest, FingerprintResponse}; pub(crate) use get_user_api_key::get_user_api_key; pub use get_user_api_key::UserApiKeyResponse; pub use secret_verification_request::SecretVerificationRequest; - -#[cfg(feature = "uniffi")] -pub mod fido2 { - pub use bitwarden_fido::*; -} diff --git a/crates/bitwarden-fido/src/authenticator.rs b/crates/bitwarden-fido/src/authenticator.rs index 4b643f132..d81ddd46c 100644 --- a/crates/bitwarden-fido/src/authenticator.rs +++ b/crates/bitwarden-fido/src/authenticator.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, VaultLocked}; use bitwarden_crypto::{CryptoError, KeyContainer, KeyEncryptable}; use bitwarden_vault::{CipherError, CipherView, Fido2CredentialView}; use log::error; @@ -73,14 +73,8 @@ pub enum SilentlyDiscoverCredentialsError { Fido2CallbackError(#[from] Fido2CallbackError), } -/// Temporary trait for solving a circular dependency. When moving `Client` to `bitwarden-core` -/// remove this trait. -pub trait FidoEncryptionSettingStore: Send + Sync { - fn get_encryption_settings(&self) -> Result, VaultLocked>; -} - pub struct Fido2Authenticator<'a> { - pub client: &'a dyn FidoEncryptionSettingStore, + pub client: &'a Client, pub user_interface: &'a dyn Fido2UserInterface, pub credential_store: &'a dyn Fido2CredentialStore, @@ -90,7 +84,7 @@ pub struct Fido2Authenticator<'a> { impl<'a> Fido2Authenticator<'a> { pub fn new( - client: &'a dyn FidoEncryptionSettingStore, + client: &'a Client, user_interface: &'a dyn Fido2UserInterface, credential_store: &'a dyn Fido2CredentialStore, ) -> Fido2Authenticator<'a> { diff --git a/crates/bitwarden-fido/src/lib.rs b/crates/bitwarden-fido/src/lib.rs index f3532a3c8..f8a5b9a50 100644 --- a/crates/bitwarden-fido/src/lib.rs +++ b/crates/bitwarden-fido/src/lib.rs @@ -15,8 +15,7 @@ mod crypto; mod traits; mod types; pub use authenticator::{ - Fido2Authenticator, FidoEncryptionSettingStore, GetAssertionError, MakeCredentialError, - SilentlyDiscoverCredentialsError, + Fido2Authenticator, GetAssertionError, MakeCredentialError, SilentlyDiscoverCredentialsError, }; pub use client::{Fido2Client, Fido2ClientError}; pub use passkey::authenticator::UIHint; diff --git a/crates/bitwarden-send/src/lib.rs b/crates/bitwarden-send/src/lib.rs index a8a8c4540..be274fcab 100644 --- a/crates/bitwarden-send/src/lib.rs +++ b/crates/bitwarden-send/src/lib.rs @@ -1,6 +1,8 @@ #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); +mod error; +pub use error::SendParseError; mod client_sends; pub use client_sends::{ClientSends, ClientSendsExt}; mod send; diff --git a/crates/bitwarden-send/src/send.rs b/crates/bitwarden-send/src/send.rs index 20031f92e..e38076302 100644 --- a/crates/bitwarden-send/src/send.rs +++ b/crates/bitwarden-send/src/send.rs @@ -3,7 +3,7 @@ use base64::{ Engine, }; use bitwarden_api_api::models::{SendFileModel, SendResponseModel, SendTextModel}; -use bitwarden_core::{require, Error}; +use bitwarden_core::require; use bitwarden_crypto::{ derive_shareable_key, generate_random_bytes, CryptoError, EncString, KeyDecryptable, KeyEncryptable, SymmetricCryptoKey, @@ -15,6 +15,8 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; use zeroize::Zeroizing; +use crate::SendParseError; + const SEND_ITERATIONS: u32 = 100_000; #[derive(Serialize, Deserialize, Debug, JsonSchema)] diff --git a/crates/bitwarden-vault/src/mobile/client_ciphers.rs b/crates/bitwarden-vault/src/mobile/client_ciphers.rs index 3a3bc1ccd..a05c81949 100644 --- a/crates/bitwarden-vault/src/mobile/client_ciphers.rs +++ b/crates/bitwarden-vault/src/mobile/client_ciphers.rs @@ -61,10 +61,12 @@ impl<'a> ClientCiphers<'a> { pub fn decrypt_fido2_credentials( &self, cipher_view: CipherView, - ) -> Result> { - let enc = self.client.get_encryption_settings()?; + ) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; - let credentials = cipher_view.decrypt_fido2_credentials(&enc)?; + let credentials = cipher_view + .decrypt_fido2_credentials(&enc) + .map_err(|e| e.to_string())?; Ok(credentials) } diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 8a6727428..a594ffa5a 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -34,7 +34,6 @@ uniffi = [ "bitwarden-generators/uniffi", "bitwarden-send/uniffi", "bitwarden-vault/uniffi", - "dep:uniffi", ] # Uniffi bindings secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API From a2928e447ce5f92e0f70f942d98ec6e913549c97 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 11:17:34 +0200 Subject: [PATCH 10/28] Resolve more merge issues --- Cargo.lock | 2 + .../bitwarden-core/src/auth/auth_request.rs | 3 +- .../src/client/encryption_settings.rs | 3 +- crates/bitwarden-core/src/client/internal.rs | 7 ++-- crates/bitwarden-core/src/mobile/crypto.rs | 3 +- crates/bitwarden-core/src/mobile/mod.rs | 1 - .../src/client_exporter.rs | 4 +- crates/bitwarden-exporters/src/models.rs | 1 - crates/bitwarden-fido/src/authenticator.rs | 2 +- .../src}/client_fido.rs | 29 ++++++++------- crates/bitwarden-fido/src/lib.rs | 2 + crates/bitwarden-json/src/client.rs | 4 +- crates/bitwarden-send/src/send.rs | 2 - crates/bitwarden-sm/src/client_projects.rs | 18 ++++----- crates/bitwarden-sm/src/client_secrets.rs | 24 ++++++------ crates/bitwarden-uniffi/src/error.rs | 6 +++ crates/bitwarden-uniffi/src/lib.rs | 2 +- crates/bitwarden-uniffi/src/platform/fido2.rs | 37 ++++++++----------- crates/bitwarden-uniffi/src/vault/ciphers.rs | 2 +- crates/bitwarden-vault/src/cipher/cipher.rs | 3 +- crates/bitwarden-vault/src/cipher/field.rs | 1 - crates/bitwarden-vault/src/client_vault.rs | 10 ++--- .../src/mobile/client_attachments.rs | 7 ++-- .../src/mobile/client_ciphers.rs | 8 ++-- .../src/mobile/client_collection.rs | 6 +-- .../src/mobile/client_folders.rs | 4 +- .../src/mobile/client_password_history.rs | 4 +- crates/bitwarden-vault/src/sync.rs | 3 +- crates/bitwarden/Cargo.toml | 3 ++ crates/bitwarden/src/lib.rs | 4 ++ 30 files changed, 102 insertions(+), 103 deletions(-) rename crates/{bitwarden-core/src/platform => bitwarden-fido/src}/client_fido.rs (64%) diff --git a/Cargo.lock b/Cargo.lock index dfbba8127..4d91eb6d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,7 +367,9 @@ dependencies = [ "bitwarden-send", "bitwarden-sm", "bitwarden-vault", + "reqwest", "thiserror", + "uniffi", ] [[package]] diff --git a/crates/bitwarden-core/src/auth/auth_request.rs b/crates/bitwarden-core/src/auth/auth_request.rs index 24a878425..fa32b27b6 100644 --- a/crates/bitwarden-core/src/auth/auth_request.rs +++ b/crates/bitwarden-core/src/auth/auth_request.rs @@ -5,8 +5,7 @@ use bitwarden_crypto::{ #[cfg(feature = "internal")] use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; -use crate::VaultLocked; -use crate::{error::Error, Client}; +use crate::{error::Error, Client, VaultLocked}; #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] pub struct AuthRequestResponse { diff --git a/crates/bitwarden-core/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs index 3116af2ce..6b781d750 100644 --- a/crates/bitwarden-core/src/client/encryption_settings.rs +++ b/crates/bitwarden-core/src/client/encryption_settings.rs @@ -72,9 +72,10 @@ impl EncryptionSettings { &mut self, org_enc_keys: Vec<(Uuid, AsymmetricEncString)>, ) -> Result<&Self> { - use crate::VaultLocked; use bitwarden_crypto::KeyDecryptable; + use crate::VaultLocked; + let private_key = self.private_key.as_ref().ok_or(VaultLocked)?; // Make sure we only keep the keys given in the arguments and not any of the previous diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index d4e30349d..3c4bda8b9 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -1,8 +1,7 @@ -use bitwarden_crypto::Kdf; -use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey, SymmetricCryptoKey}; +use std::sync::{Arc, RwLock}; + +use bitwarden_crypto::{AsymmetricEncString, EncString, Kdf, MasterKey, SymmetricCryptoKey}; use chrono::Utc; -use std::sync::Arc; -use std::sync::RwLock; use uuid::Uuid; use super::{ diff --git a/crates/bitwarden-core/src/mobile/crypto.rs b/crates/bitwarden-core/src/mobile/crypto.rs index 8ab816ffa..518690d8e 100644 --- a/crates/bitwarden-core/src/mobile/crypto.rs +++ b/crates/bitwarden-core/src/mobile/crypto.rs @@ -8,11 +8,10 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "internal")] use crate::client::{LoginMethod, UserLoginMethod}; -use crate::VaultLocked; use crate::{ client::Kdf, error::{Error, Result}, - Client, + Client, VaultLocked, }; #[cfg(feature = "internal")] diff --git a/crates/bitwarden-core/src/mobile/mod.rs b/crates/bitwarden-core/src/mobile/mod.rs index 996d98bd9..7c6a916a8 100644 --- a/crates/bitwarden-core/src/mobile/mod.rs +++ b/crates/bitwarden-core/src/mobile/mod.rs @@ -1,6 +1,5 @@ pub mod crypto; pub mod kdf; -//pub mod vault; mod client_crypto; mod client_kdf; diff --git a/crates/bitwarden-exporters/src/client_exporter.rs b/crates/bitwarden-exporters/src/client_exporter.rs index cb0c1ecf8..6d7a12f13 100644 --- a/crates/bitwarden-exporters/src/client_exporter.rs +++ b/crates/bitwarden-exporters/src/client_exporter.rs @@ -15,7 +15,7 @@ impl<'a> ClientExporters<'a> { Self { client } } - pub async fn export_vault( + pub fn export_vault( &self, folders: Vec, ciphers: Vec, @@ -24,7 +24,7 @@ impl<'a> ClientExporters<'a> { export_vault(&self.client, folders, ciphers, format) } - pub async fn export_organization_vault( + pub fn export_organization_vault( &self, collections: Vec, ciphers: Vec, diff --git a/crates/bitwarden-exporters/src/models.rs b/crates/bitwarden-exporters/src/models.rs index 28e1a7b73..e0da3b701 100644 --- a/crates/bitwarden-exporters/src/models.rs +++ b/crates/bitwarden-exporters/src/models.rs @@ -2,7 +2,6 @@ use std::fmt; use bitwarden_core::require; use bitwarden_vault::{CipherView, FieldView, FolderView, LoginUriView}; - use chrono::{DateTime, Utc}; use uuid::Uuid; diff --git a/crates/bitwarden-fido/src/authenticator.rs b/crates/bitwarden-fido/src/authenticator.rs index d81ddd46c..40434fba2 100644 --- a/crates/bitwarden-fido/src/authenticator.rs +++ b/crates/bitwarden-fido/src/authenticator.rs @@ -1,4 +1,4 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use bitwarden_core::{Client, VaultLocked}; use bitwarden_crypto::{CryptoError, KeyContainer, KeyEncryptable}; diff --git a/crates/bitwarden-core/src/platform/client_fido.rs b/crates/bitwarden-fido/src/client_fido.rs similarity index 64% rename from crates/bitwarden-core/src/platform/client_fido.rs rename to crates/bitwarden-fido/src/client_fido.rs index 63808e21b..8af0ab120 100644 --- a/crates/bitwarden-core/src/platform/client_fido.rs +++ b/crates/bitwarden-fido/src/client_fido.rs @@ -1,26 +1,17 @@ -use std::sync::Arc; +use bitwarden_core::Client; -use bitwarden_fido::{ - Fido2Authenticator, Fido2Client, Fido2CredentialStore, Fido2UserInterface, - FidoEncryptionSettingStore, -}; - -use crate::Client; +use crate::{Fido2Authenticator, Fido2Client, Fido2CredentialStore, Fido2UserInterface}; pub struct ClientFido2<'a> { #[allow(dead_code)] pub(crate) client: &'a Client, } -impl FidoEncryptionSettingStore for Client { - fn get_encryption_settings( - &self, - ) -> Result, bitwarden_core::VaultLocked> { - Ok(self.get_encryption_settings()?) +impl<'a> ClientFido2<'a> { + pub fn new(client: &'a Client) -> Self { + Self { client } } -} -impl<'a> ClientFido2<'a> { pub fn create_authenticator( &'a self, user_interface: &'a dyn Fido2UserInterface, @@ -39,3 +30,13 @@ impl<'a> ClientFido2<'a> { } } } + +pub trait ClientFido2Ext<'a> { + fn fido2(&'a self) -> ClientFido2<'a>; +} + +impl<'a> ClientFido2Ext<'a> for Client { + fn fido2(&'a self) -> ClientFido2<'a> { + ClientFido2::new(self) + } +} diff --git a/crates/bitwarden-fido/src/lib.rs b/crates/bitwarden-fido/src/lib.rs index f8a5b9a50..e1c0c9eab 100644 --- a/crates/bitwarden-fido/src/lib.rs +++ b/crates/bitwarden-fido/src/lib.rs @@ -11,6 +11,7 @@ uniffi::setup_scaffolding!(); mod authenticator; mod client; +mod client_fido; mod crypto; mod traits; mod types; @@ -18,6 +19,7 @@ pub use authenticator::{ Fido2Authenticator, GetAssertionError, MakeCredentialError, SilentlyDiscoverCredentialsError, }; pub use client::{Fido2Client, Fido2ClientError}; +pub use client_fido::{ClientFido2, ClientFido2Ext}; pub use passkey::authenticator::UIHint; use thiserror::Error; pub use traits::{ diff --git a/crates/bitwarden-json/src/client.rs b/crates/bitwarden-json/src/client.rs index b29414f6f..536693663 100644 --- a/crates/bitwarden-json/src/client.rs +++ b/crates/bitwarden-json/src/client.rs @@ -1,10 +1,8 @@ -use async_lock::Mutex; #[cfg(feature = "secrets")] use bitwarden::secrets_manager::{ClientProjectsExt, ClientSecretsExt}; -use bitwarden::ClientSettings; - #[cfg(feature = "internal")] use bitwarden::vault::ClientVaultExt; +use bitwarden::ClientSettings; #[cfg(feature = "secrets")] use crate::command::{ProjectsCommand, SecretsCommand}; diff --git a/crates/bitwarden-send/src/send.rs b/crates/bitwarden-send/src/send.rs index e38076302..452032cf6 100644 --- a/crates/bitwarden-send/src/send.rs +++ b/crates/bitwarden-send/src/send.rs @@ -359,7 +359,6 @@ impl TryFrom for SendText { } } -/* #[cfg(test)] mod tests { use std::collections::HashMap; @@ -600,4 +599,3 @@ mod tests { assert!(v.has_password); } } -*/ diff --git a/crates/bitwarden-sm/src/client_projects.rs b/crates/bitwarden-sm/src/client_projects.rs index 038221fe2..13b2c6967 100644 --- a/crates/bitwarden-sm/src/client_projects.rs +++ b/crates/bitwarden-sm/src/client_projects.rs @@ -7,32 +7,32 @@ use crate::projects::{ }; pub struct ClientProjects<'a> { - pub client: &'a mut Client, + pub client: &'a Client, } impl<'a> ClientProjects<'a> { - pub fn new(client: &'a mut Client) -> Self { + pub fn new(client: &'a Client) -> Self { Self { client } } - pub async fn get(&mut self, input: &ProjectGetRequest) -> Result { + pub async fn get(&self, input: &ProjectGetRequest) -> Result { get_project(self.client, input).await } - pub async fn create(&mut self, input: &ProjectCreateRequest) -> Result { + pub async fn create(&self, input: &ProjectCreateRequest) -> Result { create_project(self.client, input).await } - pub async fn list(&mut self, input: &ProjectsListRequest) -> Result { + pub async fn list(&self, input: &ProjectsListRequest) -> Result { list_projects(self.client, input).await } - pub async fn update(&mut self, input: &ProjectPutRequest) -> Result { + pub async fn update(&self, input: &ProjectPutRequest) -> Result { update_project(self.client, input).await } pub async fn delete( - &mut self, + &self, input: ProjectsDeleteRequest, ) -> Result { delete_projects(self.client, input).await @@ -40,11 +40,11 @@ impl<'a> ClientProjects<'a> { } pub trait ClientProjectsExt<'a> { - fn projects(&'a mut self) -> ClientProjects<'a>; + fn projects(&'a self) -> ClientProjects<'a>; } impl<'a> ClientProjectsExt<'a> for Client { - fn projects(&'a mut self) -> ClientProjects<'a> { + fn projects(&'a self) -> ClientProjects<'a> { ClientProjects::new(self) } } diff --git a/crates/bitwarden-sm/src/client_secrets.rs b/crates/bitwarden-sm/src/client_secrets.rs index 960f60984..2b1085a0a 100644 --- a/crates/bitwarden-sm/src/client_secrets.rs +++ b/crates/bitwarden-sm/src/client_secrets.rs @@ -9,62 +9,62 @@ use crate::secrets::{ }; pub struct ClientSecrets<'a> { - client: &'a mut Client, + client: &'a Client, } impl<'a> ClientSecrets<'a> { - pub fn new(client: &'a mut Client) -> Self { + pub fn new(client: &'a Client) -> Self { Self { client } } - pub async fn get(&mut self, input: &SecretGetRequest) -> Result { + pub async fn get(&self, input: &SecretGetRequest) -> Result { get_secret(self.client, input).await } - pub async fn get_by_ids(&mut self, input: SecretsGetRequest) -> Result { + pub async fn get_by_ids(&self, input: SecretsGetRequest) -> Result { get_secrets_by_ids(self.client, input).await } - pub async fn create(&mut self, input: &SecretCreateRequest) -> Result { + pub async fn create(&self, input: &SecretCreateRequest) -> Result { create_secret(self.client, input).await } pub async fn list( - &mut self, + &self, input: &SecretIdentifiersRequest, ) -> Result { list_secrets(self.client, input).await } pub async fn list_by_project( - &mut self, + &self, input: &SecretIdentifiersByProjectRequest, ) -> Result { list_secrets_by_project(self.client, input).await } - pub async fn update(&mut self, input: &SecretPutRequest) -> Result { + pub async fn update(&self, input: &SecretPutRequest) -> Result { update_secret(self.client, input).await } pub async fn delete( - &mut self, + &self, input: SecretsDeleteRequest, ) -> Result { delete_secrets(self.client, input).await } - pub async fn sync(&mut self, input: &SecretsSyncRequest) -> Result { + pub async fn sync(&self, input: &SecretsSyncRequest) -> Result { sync_secrets(self.client, input).await } } pub trait ClientSecretsExt<'a> { - fn secrets(&'a mut self) -> ClientSecrets<'a>; + fn secrets(&'a self) -> ClientSecrets<'a>; } impl<'a> ClientSecretsExt<'a> for Client { - fn secrets(&'a mut self) -> ClientSecrets<'a> { + fn secrets(&'a self) -> ClientSecrets<'a> { ClientSecrets::new(self) } } diff --git a/crates/bitwarden-uniffi/src/error.rs b/crates/bitwarden-uniffi/src/error.rs index 1b1aa8505..cb854b498 100644 --- a/crates/bitwarden-uniffi/src/error.rs +++ b/crates/bitwarden-uniffi/src/error.rs @@ -17,6 +17,12 @@ impl From for BitwardenError { } } +impl From for BitwardenError { + fn from(e: bitwarden::error::Error) -> Self { + Self::E2(e) + } +} + impl From for BitwardenError { fn from(e: bitwarden::exporters::ExportError) -> Self { Self::Ee(e) diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index ed426f30d..eb71f0bbf 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -8,7 +8,7 @@ use bitwarden::ClientSettings; pub mod auth; pub mod crypto; mod error; -//pub mod platform; +pub mod platform; pub mod tool; mod uniffi_support; pub mod vault; diff --git a/crates/bitwarden-uniffi/src/platform/fido2.rs b/crates/bitwarden-uniffi/src/platform/fido2.rs index 09162b7d0..317a13a2b 100644 --- a/crates/bitwarden-uniffi/src/platform/fido2.rs +++ b/crates/bitwarden-uniffi/src/platform/fido2.rs @@ -2,8 +2,8 @@ use std::sync::Arc; use bitwarden::{ error::Error, - platform::fido2::{ - CheckUserOptions, ClientData, Fido2CallbackError as BitFido2CallbackError, + fido::{ + CheckUserOptions, ClientData, ClientFido2Ext, Fido2CallbackError as BitFido2CallbackError, GetAssertionRequest, GetAssertionResult, MakeCredentialRequest, MakeCredentialResult, PublicKeyCredentialAuthenticatorAssertionResponse, PublicKeyCredentialAuthenticatorAttestationResponse, PublicKeyCredentialRpEntity, @@ -57,8 +57,7 @@ impl ClientFido2Authenticator { &self, request: MakeCredentialRequest, ) -> Result { - let platform = self.0 .0.platform(); - let fido2 = platform.fido2(); + let fido2 = self.0 .0.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -71,8 +70,7 @@ impl ClientFido2Authenticator { } pub async fn get_assertion(&self, request: GetAssertionRequest) -> Result { - let platform = self.0 .0.platform(); - let fido2 = platform.fido2(); + let fido2 = self.0 .0.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -88,8 +86,7 @@ impl ClientFido2Authenticator { &self, rp_id: String, ) -> Result> { - let platform = self.0 .0.platform(); - let fido2 = platform.fido2(); + let fido2 = self.0 .0.fido2(); let ui = UniffiTraitBridge(self.1.as_ref()); let cs = UniffiTraitBridge(self.2.as_ref()); let mut auth = fido2.create_authenticator(&ui, &cs); @@ -113,8 +110,7 @@ impl ClientFido2Client { request: String, client_data: ClientData, ) -> Result { - let platform = self.0 .0 .0.platform(); - let fido2 = platform.fido2(); + let fido2 = self.0 .0 .0.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); @@ -132,8 +128,7 @@ impl ClientFido2Client { request: String, client_data: ClientData, ) -> Result { - let platform = self.0 .0 .0.platform(); - let fido2 = platform.fido2(); + let fido2 = self.0 .0 .0.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); @@ -226,9 +221,7 @@ pub trait Fido2CredentialStore: Send + Sync { struct UniffiTraitBridge(T); #[async_trait::async_trait] -impl bitwarden::platform::fido2::Fido2CredentialStore - for UniffiTraitBridge<&dyn Fido2CredentialStore> -{ +impl bitwarden::fido::Fido2CredentialStore for UniffiTraitBridge<&dyn Fido2CredentialStore> { async fn find_credentials( &self, ids: Option>>, @@ -262,9 +255,9 @@ pub enum UIHint { RequestExistingCredential(CipherView), } -impl From> for UIHint { - fn from(hint: bitwarden::platform::fido2::UIHint<'_, CipherView>) -> Self { - use bitwarden::platform::fido2::UIHint as BWUIHint; +impl From> for UIHint { + fn from(hint: bitwarden::fido::UIHint<'_, CipherView>) -> Self { + use bitwarden::fido::UIHint as BWUIHint; match hint { BWUIHint::InformExcludedCredentialFound(cipher) => { UIHint::InformExcludedCredentialFound(cipher.clone()) @@ -289,16 +282,16 @@ impl From> for UIHint { } #[async_trait::async_trait] -impl bitwarden::platform::fido2::Fido2UserInterface for UniffiTraitBridge<&dyn Fido2UserInterface> { +impl bitwarden::fido::Fido2UserInterface for UniffiTraitBridge<&dyn Fido2UserInterface> { async fn check_user<'a>( &self, options: CheckUserOptions, - hint: bitwarden::platform::fido2::UIHint<'a, CipherView>, - ) -> Result { + hint: bitwarden::fido::UIHint<'a, CipherView>, + ) -> Result { self.0 .check_user(options.clone(), hint.into()) .await - .map(|r| bitwarden::platform::fido2::CheckUserResult { + .map(|r| bitwarden::fido::CheckUserResult { user_present: r.user_present, user_verified: r.user_verified, }) diff --git a/crates/bitwarden-uniffi/src/vault/ciphers.rs b/crates/bitwarden-uniffi/src/vault/ciphers.rs index f94e9b431..790de4c3b 100644 --- a/crates/bitwarden-uniffi/src/vault/ciphers.rs +++ b/crates/bitwarden-uniffi/src/vault/ciphers.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use bitwarden::vault::{Cipher, CipherListView, CipherView, ClientVaultExt}; +use bitwarden_vault::Fido2CredentialView; use uuid::Uuid; use crate::{error::BitwardenError, Client, Result}; @@ -49,7 +50,6 @@ impl ClientCiphers { .vault() .ciphers() .move_to_organization(cipher, organization_id) - .await .map_err(|e| BitwardenError::E2(bitwarden::error::Error::Cipher(e)))?) } } diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index 5de6a1140..32ba01afa 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -612,9 +612,8 @@ mod tests { use attachment::AttachmentView; - use crate::Fido2Credential; - use super::*; + use crate::Fido2Credential; fn generate_cipher() -> CipherView { CipherView { diff --git a/crates/bitwarden-vault/src/cipher/field.rs b/crates/bitwarden-vault/src/cipher/field.rs index 8fea90eea..6c826d4ba 100644 --- a/crates/bitwarden-vault/src/cipher/field.rs +++ b/crates/bitwarden-vault/src/cipher/field.rs @@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use super::linked_id::LinkedIdType; - use crate::VaultParseError; #[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug, JsonSchema)] diff --git a/crates/bitwarden-vault/src/client_vault.rs b/crates/bitwarden-vault/src/client_vault.rs index d0ca77175..67f6792b9 100644 --- a/crates/bitwarden-vault/src/client_vault.rs +++ b/crates/bitwarden-vault/src/client_vault.rs @@ -6,25 +6,25 @@ use crate::{ }; pub struct ClientVault<'a> { - pub(crate) client: &'a mut Client, + pub(crate) client: &'a Client, } impl<'a> ClientVault<'a> { - pub fn new(client: &'a mut Client) -> Self { + pub fn new(client: &'a Client) -> Self { Self { client } } - pub async fn sync(&mut self, input: &SyncRequest) -> Result { + pub async fn sync(&self, input: &SyncRequest) -> Result { sync(self.client, input).await } } pub trait ClientVaultExt<'a> { - fn vault(&'a mut self) -> ClientVault<'a>; + fn vault(&'a self) -> ClientVault<'a>; } impl<'a> ClientVaultExt<'a> for Client { - fn vault(&'a mut self) -> ClientVault<'a> { + fn vault(&'a self) -> ClientVault<'a> { ClientVault::new(self) } } diff --git a/crates/bitwarden-vault/src/mobile/client_attachments.rs b/crates/bitwarden-vault/src/mobile/client_attachments.rs index e3b408d86..f382075ec 100644 --- a/crates/bitwarden-vault/src/mobile/client_attachments.rs +++ b/crates/bitwarden-vault/src/mobile/client_attachments.rs @@ -1,13 +1,12 @@ use std::path::Path; +use bitwarden_core::{Client, Error, VaultLocked}; +use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey}; + use crate::{ Attachment, AttachmentEncryptResult, AttachmentFile, AttachmentFileView, AttachmentView, Cipher, ClientVault, }; -use bitwarden_core::VaultLocked; -use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey}; - -use bitwarden_core::{Client, Error}; pub struct ClientAttachments<'a> { pub(crate) client: &'a Client, diff --git a/crates/bitwarden-vault/src/mobile/client_ciphers.rs b/crates/bitwarden-vault/src/mobile/client_ciphers.rs index a05c81949..864af8b94 100644 --- a/crates/bitwarden-vault/src/mobile/client_ciphers.rs +++ b/crates/bitwarden-vault/src/mobile/client_ciphers.rs @@ -1,9 +1,8 @@ -use crate::{Cipher, CipherError, CipherListView, CipherView, ClientVault}; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable, LocateKey}; use uuid::Uuid; -use bitwarden_core::{Client, Error}; +use crate::{Cipher, CipherError, CipherListView, CipherView, ClientVault}; pub struct ClientCiphers<'a> { pub(crate) client: &'a Client, @@ -95,9 +94,8 @@ mod tests { use bitwarden_core::client::test_accounts::test_bitwarden_com_account; - use crate::{Attachment, CipherRepromptType, CipherType, ClientVaultExt, Login}; - use super::*; + use crate::{Attachment, CipherRepromptType, CipherType, ClientVaultExt, Login}; #[tokio::test] async fn test_decrypt_list() { diff --git a/crates/bitwarden-vault/src/mobile/client_collection.rs b/crates/bitwarden-vault/src/mobile/client_collection.rs index d0a4c0784..42cda4bc5 100644 --- a/crates/bitwarden-vault/src/mobile/client_collection.rs +++ b/crates/bitwarden-vault/src/mobile/client_collection.rs @@ -1,7 +1,8 @@ -use crate::{ClientVault, Collection, CollectionView}; use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, LocateKey}; +use crate::{ClientVault, Collection, CollectionView}; + pub struct ClientCollections<'a> { pub(crate) client: &'a Client, } @@ -45,9 +46,8 @@ impl<'a> ClientVault<'a> { mod tests { use bitwarden_core::client::test_accounts::test_bitwarden_com_account; - use crate::ClientVaultExt; - use super::*; + use crate::ClientVaultExt; #[tokio::test] async fn test_decrypt_list() { diff --git a/crates/bitwarden-vault/src/mobile/client_folders.rs b/crates/bitwarden-vault/src/mobile/client_folders.rs index d40f21105..93d89c4d6 100644 --- a/crates/bitwarden-vault/src/mobile/client_folders.rs +++ b/crates/bitwarden-vault/src/mobile/client_folders.rs @@ -1,7 +1,7 @@ -use crate::{ClientVault, Folder, FolderView}; +use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable}; -use bitwarden_core::{Client, Error}; +use crate::{ClientVault, Folder, FolderView}; pub struct ClientFolders<'a> { pub(crate) client: &'a Client, diff --git a/crates/bitwarden-vault/src/mobile/client_password_history.rs b/crates/bitwarden-vault/src/mobile/client_password_history.rs index 7aa10d276..8af07a120 100644 --- a/crates/bitwarden-vault/src/mobile/client_password_history.rs +++ b/crates/bitwarden-vault/src/mobile/client_password_history.rs @@ -1,7 +1,7 @@ -use crate::{ClientVault, PasswordHistory, PasswordHistoryView}; +use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable}; -use bitwarden_core::{Client, Error}; +use crate::{ClientVault, PasswordHistory, PasswordHistoryView}; pub struct ClientPasswordHistory<'a> { pub(crate) client: &'a Client, diff --git a/crates/bitwarden-vault/src/sync.rs b/crates/bitwarden-vault/src/sync.rs index 79633e5b6..6b4845d35 100644 --- a/crates/bitwarden-vault/src/sync.rs +++ b/crates/bitwarden-vault/src/sync.rs @@ -1,4 +1,3 @@ -use crate::{Cipher, Collection, Folder, GlobalDomains, VaultParseError}; use bitwarden_api_api::models::{ DomainsResponseModel, ProfileOrganizationResponseModel, ProfileResponseModel, SyncResponseModel, }; @@ -10,6 +9,8 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use uuid::Uuid; +use crate::{Cipher, Collection, Folder, GlobalDomains, VaultParseError}; + #[derive(Debug, Error)] pub enum SyncError { #[error(transparent)] diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index a594ffa5a..214d7c0f0 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -34,6 +34,7 @@ uniffi = [ "bitwarden-generators/uniffi", "bitwarden-send/uniffi", "bitwarden-vault/uniffi", + "dep:uniffi", ] # Uniffi bindings secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API @@ -49,6 +50,8 @@ bitwarden-send = { workspace = true, optional = true } bitwarden-sm = { workspace = true, optional = true } bitwarden-vault = { workspace = true, optional = true } thiserror = ">=1.0.40, <2.0" +reqwest = { version = ">=0.12, <0.13", default-features = false } +uniffi = { version = "=0.27.2", optional = true, features = ["tokio"] } [lints] workspace = true diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index 10b607b45..55d8bad6a 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -18,6 +18,10 @@ pub mod internal { pub mod vault { pub use bitwarden_vault::*; } + + pub mod fido { + pub use bitwarden_fido::*; + } } #[cfg(feature = "internal")] pub use internal::*; From 54d97cd9df7dbb5bb1d25e315bf672b348b4abd4 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 13:50:55 +0200 Subject: [PATCH 11/28] Undo some moves --- crates/bitwarden-exporters/src/csv.rs | 4 +- .../bitwarden-exporters/src/encrypted_json.rs | 4 +- crates/bitwarden-exporters/src/export.rs | 6 +- crates/bitwarden-exporters/src/json.rs | 6 +- crates/bitwarden-exporters/src/lib.rs | 124 ++++++++++++- crates/bitwarden-exporters/src/models.rs | 174 +++--------------- 6 files changed, 156 insertions(+), 162 deletions(-) diff --git a/crates/bitwarden-exporters/src/csv.rs b/crates/bitwarden-exporters/src/csv.rs index 30c56f74a..a0dcd1040 100644 --- a/crates/bitwarden-exporters/src/csv.rs +++ b/crates/bitwarden-exporters/src/csv.rs @@ -5,7 +5,7 @@ use serde::Serializer; use thiserror::Error; use uuid::Uuid; -use crate::models::{Cipher, CipherType, Field, Folder}; +use crate::{Cipher, CipherType, Field, Folder}; #[derive(Debug, Error)] pub enum CsvError { @@ -111,7 +111,7 @@ where #[cfg(test)] mod tests { use super::*; - use crate::models::{Card, Identity, Login, LoginUri}; + use crate::{Card, Identity, Login, LoginUri}; #[test] fn test_export_csv() { diff --git a/crates/bitwarden-exporters/src/encrypted_json.rs b/crates/bitwarden-exporters/src/encrypted_json.rs index a4b4901c1..0378bd9f3 100644 --- a/crates/bitwarden-exporters/src/encrypted_json.rs +++ b/crates/bitwarden-exporters/src/encrypted_json.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use crate::{ json::{self, export_json}, - models::{Cipher, Folder}, + Cipher, Folder, }; #[derive(Error, Debug)] @@ -84,7 +84,7 @@ mod tests { use std::num::NonZeroU32; use super::*; - use crate::models::{ + use crate::{ Card, Cipher, CipherType, Field, Identity, Login, LoginUri, SecureNote, SecureNoteType, }; diff --git a/crates/bitwarden-exporters/src/export.rs b/crates/bitwarden-exporters/src/export.rs index 95a552a6d..0721ae11f 100644 --- a/crates/bitwarden-exporters/src/export.rs +++ b/crates/bitwarden-exporters/src/export.rs @@ -17,12 +17,10 @@ pub(crate) fn export_vault( let key = enc.get_key(&None).ok_or(VaultLocked)?; let folders: Vec = folders.decrypt_with_key(key)?; - let folders: Vec = - folders.into_iter().flat_map(|f| f.try_into()).collect(); + let folders: Vec = folders.into_iter().flat_map(|f| f.try_into()).collect(); let ciphers: Vec = ciphers.decrypt_with_key(key)?; - let ciphers: Vec = - ciphers.into_iter().flat_map(|c| c.try_into()).collect(); + let ciphers: Vec = ciphers.into_iter().flat_map(|c| c.try_into()).collect(); match format { ExportFormat::Csv => Ok(export_csv(folders, ciphers)?), diff --git a/crates/bitwarden-exporters/src/json.rs b/crates/bitwarden-exporters/src/json.rs index 71e7a374d..3f6c72c1f 100644 --- a/crates/bitwarden-exporters/src/json.rs +++ b/crates/bitwarden-exporters/src/json.rs @@ -2,9 +2,7 @@ use chrono::{DateTime, Utc}; use thiserror::Error; use uuid::Uuid; -use crate::models::{ - Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote, -}; +use crate::{Card, Cipher, CipherType, Field, Folder, Identity, Login, LoginUri, SecureNote}; #[derive(Error, Debug)] pub enum JsonError { @@ -272,7 +270,7 @@ mod tests { use std::{fs, io::Read, path::PathBuf}; use super::*; - use crate::models::{Cipher, Field, LoginUri, SecureNoteType}; + use crate::{Cipher, Field, LoginUri, SecureNoteType}; #[test] fn test_convert_login() { diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index 3db5ceffc..75b0503e2 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -1,17 +1,21 @@ +use std::fmt; + +use chrono::{DateTime, Utc}; use schemars::JsonSchema; +use uuid::Uuid; + +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!(); mod client_exporter; mod csv; +mod encrypted_json; mod json; +mod models; pub use client_exporter::{ClientExporters, ClientExportersExt}; -mod encrypted_json; mod error; -pub(crate) mod export; +mod export; pub use error::ExportError; -mod models; - -#[cfg(feature = "uniffi")] -uniffi::setup_scaffolding!(); #[derive(JsonSchema)] #[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] @@ -20,3 +24,111 @@ pub enum ExportFormat { Json, EncryptedJson { password: String }, } + +/// Export representation of a Bitwarden folder. +/// +/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API +/// that is not tied to the internal vault models. We may revisit this in the future. +pub struct Folder { + pub id: Uuid, + pub name: String, +} + +/// Export representation of a Bitwarden cipher. +/// +/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API +/// that is not tied to the internal vault models. We may revisit this in the future. +pub struct Cipher { + pub id: Uuid, + pub folder_id: Option, + + pub name: String, + pub notes: Option, + + pub r#type: CipherType, + + pub favorite: bool, + pub reprompt: u8, + + pub fields: Vec, + + pub revision_date: DateTime, + pub creation_date: DateTime, + pub deleted_date: Option>, +} + +#[derive(Clone)] +pub struct Field { + pub name: Option, + pub value: Option, + pub r#type: u8, + pub linked_id: Option, +} + +pub enum CipherType { + Login(Box), + SecureNote(Box), + Card(Box), + Identity(Box), +} + +impl fmt::Display for CipherType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + CipherType::Login(_) => write!(f, "login"), + CipherType::SecureNote(_) => write!(f, "note"), + CipherType::Card(_) => write!(f, "card"), + CipherType::Identity(_) => write!(f, "identity"), + } + } +} + +pub struct Login { + pub username: Option, + pub password: Option, + pub login_uris: Vec, + pub totp: Option, +} + +pub struct LoginUri { + pub uri: Option, + pub r#match: Option, +} + +pub struct Card { + pub cardholder_name: Option, + pub exp_month: Option, + pub exp_year: Option, + pub code: Option, + pub brand: Option, + pub number: Option, +} + +pub struct SecureNote { + pub r#type: SecureNoteType, +} + +pub enum SecureNoteType { + Generic = 0, +} + +pub struct Identity { + pub title: Option, + pub first_name: Option, + pub middle_name: Option, + pub last_name: Option, + pub address1: Option, + pub address2: Option, + pub address3: Option, + pub city: Option, + pub state: Option, + pub postal_code: Option, + pub country: Option, + pub company: Option, + pub email: Option, + pub phone: Option, + pub ssn: Option, + pub username: Option, + pub passport_number: Option, + pub license_number: Option, +} diff --git a/crates/bitwarden-exporters/src/models.rs b/crates/bitwarden-exporters/src/models.rs index e0da3b701..1d56e7233 100644 --- a/crates/bitwarden-exporters/src/models.rs +++ b/crates/bitwarden-exporters/src/models.rs @@ -1,122 +1,10 @@ -use std::fmt; +use bitwarden_core::{require, MissingFieldError}; +use bitwarden_vault::{ + CipherType, CipherView, FieldView, FolderView, LoginUriView, SecureNoteType, +}; -use bitwarden_core::require; -use bitwarden_vault::{CipherView, FieldView, FolderView, LoginUriView}; -use chrono::{DateTime, Utc}; -use uuid::Uuid; - -use crate::ExportError; - -/// Export representation of a Bitwarden folder. -/// -/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API -/// that is not tied to the internal vault models. We may revisit this in the future. -pub(crate) struct Folder { - pub id: Uuid, - pub name: String, -} - -/// Export representation of a Bitwarden cipher. -/// -/// These are mostly duplicated from the `bitwarden` vault models to facilitate a stable export API -/// that is not tied to the internal vault models. We may revisit this in the future. -pub(crate) struct Cipher { - pub id: Uuid, - pub folder_id: Option, - - pub name: String, - pub notes: Option, - - pub r#type: CipherType, - - pub favorite: bool, - pub reprompt: u8, - - pub fields: Vec, - - pub revision_date: DateTime, - pub creation_date: DateTime, - pub deleted_date: Option>, -} - -#[derive(Clone)] -pub(crate) struct Field { - pub name: Option, - pub value: Option, - pub r#type: u8, - pub linked_id: Option, -} - -pub(crate) enum CipherType { - Login(Box), - SecureNote(Box), - Card(Box), - Identity(Box), -} - -impl fmt::Display for CipherType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - CipherType::Login(_) => write!(f, "login"), - CipherType::SecureNote(_) => write!(f, "note"), - CipherType::Card(_) => write!(f, "card"), - CipherType::Identity(_) => write!(f, "identity"), - } - } -} - -pub(crate) struct Login { - pub username: Option, - pub password: Option, - pub login_uris: Vec, - pub totp: Option, -} - -pub(crate) struct LoginUri { - pub uri: Option, - pub r#match: Option, -} - -pub(crate) struct Card { - pub cardholder_name: Option, - pub exp_month: Option, - pub exp_year: Option, - pub code: Option, - pub brand: Option, - pub number: Option, -} - -pub(crate) struct SecureNote { - pub r#type: SecureNoteType, -} - -pub(crate) enum SecureNoteType { - Generic = 0, -} - -pub(crate) struct Identity { - pub title: Option, - pub first_name: Option, - pub middle_name: Option, - pub last_name: Option, - pub address1: Option, - pub address2: Option, - pub address3: Option, - pub city: Option, - pub state: Option, - pub postal_code: Option, - pub country: Option, - pub company: Option, - pub email: Option, - pub phone: Option, - pub ssn: Option, - pub username: Option, - pub passport_number: Option, - pub license_number: Option, -} - -impl TryFrom for Folder { - type Error = ExportError; +impl TryFrom for crate::Folder { + type Error = MissingFieldError; fn try_from(value: FolderView) -> Result { Ok(Self { @@ -126,14 +14,14 @@ impl TryFrom for Folder { } } -impl TryFrom for Cipher { - type Error = ExportError; +impl TryFrom for crate::Cipher { + type Error = MissingFieldError; fn try_from(value: CipherView) -> Result { let r = match value.r#type { - bitwarden_vault::CipherType::Login => { + CipherType::Login => { let l = require!(value.login); - CipherType::Login(Box::new(Login { + crate::CipherType::Login(Box::new(crate::Login { username: l.username, password: l.password, login_uris: l @@ -145,18 +33,16 @@ impl TryFrom for Cipher { totp: l.totp, })) } - bitwarden_vault::CipherType::SecureNote => { - CipherType::SecureNote(Box::new(SecureNote { - r#type: value - .secure_note - .map(|t| t.r#type) - .unwrap_or(bitwarden_vault::SecureNoteType::Generic) - .into(), - })) - } - bitwarden_vault::CipherType::Card => { + CipherType::SecureNote => crate::CipherType::SecureNote(Box::new(crate::SecureNote { + r#type: value + .secure_note + .map(|t| t.r#type) + .unwrap_or(SecureNoteType::Generic) + .into(), + })), + CipherType::Card => { let c = require!(value.card); - CipherType::Card(Box::new(Card { + crate::CipherType::Card(Box::new(crate::Card { cardholder_name: c.cardholder_name, exp_month: c.exp_month, exp_year: c.exp_year, @@ -165,9 +51,9 @@ impl TryFrom for Cipher { number: c.number, })) } - bitwarden_vault::CipherType::Identity => { + CipherType::Identity => { let i = require!(value.identity); - CipherType::Identity(Box::new(Identity { + crate::CipherType::Identity(Box::new(crate::Identity { title: i.title, first_name: i.first_name, middle_name: i.middle_name, @@ -211,7 +97,7 @@ impl TryFrom for Cipher { } } -impl From for Field { +impl From for crate::Field { fn from(value: FieldView) -> Self { Self { name: value.name, @@ -222,7 +108,7 @@ impl From for Field { } } -impl From for LoginUri { +impl From for crate::LoginUri { fn from(value: LoginUriView) -> Self { Self { r#match: value.r#match.map(|v| v as u8), @@ -231,10 +117,10 @@ impl From for LoginUri { } } -impl From for SecureNoteType { - fn from(value: bitwarden_vault::SecureNoteType) -> Self { +impl From for crate::SecureNoteType { + fn from(value: SecureNoteType) -> Self { match value { - bitwarden_vault::SecureNoteType::Generic => SecureNoteType::Generic, + SecureNoteType::Generic => crate::SecureNoteType::Generic, } } } @@ -254,7 +140,7 @@ mod tests { revision_date: "2024-01-30T17:55:36.150Z".parse().unwrap(), }; - let f: Folder = view.try_into().unwrap(); + let f: crate::Folder = view.try_into().unwrap(); assert_eq!( f.id, @@ -266,7 +152,7 @@ mod tests { #[test] fn test_try_from_cipher_view_login() { let cipher_view = CipherView { - r#type: bitwarden_vault::CipherType::Login, + r#type: CipherType::Login, login: Some(LoginView { username: Some("test_username".to_string()), password: Some("test_password".to_string()), @@ -300,7 +186,7 @@ mod tests { revision_date: "2024-01-30T17:55:36.150Z".parse().unwrap(), }; - let cipher: Cipher = cipher_view.try_into().unwrap(); + let cipher: crate::Cipher = cipher_view.try_into().unwrap(); assert_eq!( cipher.id, @@ -322,7 +208,7 @@ mod tests { ); assert_eq!(cipher.deleted_date, None); - if let CipherType::Login(l) = cipher.r#type { + if let crate::CipherType::Login(l) = cipher.r#type { assert_eq!(l.username, Some("test_username".to_string())); assert_eq!(l.password, Some("test_password".to_string())); assert!(l.login_uris.is_empty()); From 7be92175c08ba1f53a4762977dd45ac22e7d698c Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 13:59:18 +0200 Subject: [PATCH 12/28] Fix clippy --- .../src/auth/login/access_token.rs | 2 +- .../bitwarden-core/src/auth/login/api_key.rs | 2 +- .../src/auth/login/auth_request.rs | 4 +- crates/bitwarden-core/src/auth/login/mod.rs | 2 +- .../bitwarden-core/src/auth/login/password.rs | 2 +- .../src/auth/login/two_factor.rs | 2 +- .../src/auth/password/validate.rs | 6 +-- crates/bitwarden-core/src/auth/register.rs | 2 +- crates/bitwarden-core/src/client/internal.rs | 2 +- crates/bitwarden-core/src/lib.rs | 54 ------------------- .../src/platform/get_user_api_key.rs | 2 +- crates/bitwarden-sm/src/projects/create.rs | 2 +- crates/bitwarden-sm/src/projects/delete.rs | 2 +- crates/bitwarden-sm/src/projects/get.rs | 2 +- crates/bitwarden-sm/src/projects/list.rs | 2 +- crates/bitwarden-sm/src/projects/update.rs | 2 +- crates/bitwarden-sm/src/secrets/create.rs | 2 +- crates/bitwarden-sm/src/secrets/delete.rs | 2 +- crates/bitwarden-sm/src/secrets/get.rs | 2 +- crates/bitwarden-sm/src/secrets/get_by_ids.rs | 2 +- crates/bitwarden-sm/src/secrets/list.rs | 4 +- crates/bitwarden-sm/src/secrets/sync.rs | 2 +- crates/bitwarden-sm/src/secrets/update.rs | 2 +- crates/bitwarden-vault/src/sync.rs | 2 +- 24 files changed, 27 insertions(+), 81 deletions(-) diff --git a/crates/bitwarden-core/src/auth/login/access_token.rs b/crates/bitwarden-core/src/auth/login/access_token.rs index c445e43c7..0b16a6515 100644 --- a/crates/bitwarden-core/src/auth/login/access_token.rs +++ b/crates/bitwarden-core/src/auth/login/access_token.rs @@ -106,7 +106,7 @@ async fn request_access_token( client: &Client, input: &AccessToken, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); AccessTokenRequest::new(input.access_token_id, &input.client_secret) .send(&config) .await diff --git a/crates/bitwarden-core/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs index b0e2c8834..089a0e1c3 100644 --- a/crates/bitwarden-core/src/auth/login/api_key.rs +++ b/crates/bitwarden-core/src/auth/login/api_key.rs @@ -64,7 +64,7 @@ async fn request_api_identity_tokens( client: &Client, input: &ApiKeyLoginRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); ApiTokenRequest::new(&input.client_id, &input.client_secret) .send(&config) .await diff --git a/crates/bitwarden-core/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs index 912105db0..0501a124f 100644 --- a/crates/bitwarden-core/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -30,7 +30,7 @@ pub(crate) async fn send_new_auth_request( email: String, device_identifier: String, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let auth = new_auth_request(&email)?; @@ -58,7 +58,7 @@ pub(crate) async fn complete_auth_request( client: &Client, auth_req: NewAuthRequestResponse, ) -> Result<()> { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = auth_requests_id_response_get( &config.api, diff --git a/crates/bitwarden-core/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs index 04c2804b6..fac318df1 100644 --- a/crates/bitwarden-core/src/auth/login/mod.rs +++ b/crates/bitwarden-core/src/auth/login/mod.rs @@ -49,7 +49,7 @@ pub(crate) async fn request_prelogin( email: String, ) -> Result { let request_model = PreloginRequestModel::new(email); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); Ok(accounts_prelogin_post(&config.identity, Some(request_model)).await?) } diff --git a/crates/bitwarden-core/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs index c5d32bdaf..ed93fede9 100644 --- a/crates/bitwarden-core/src/auth/login/password.rs +++ b/crates/bitwarden-core/src/auth/login/password.rs @@ -71,7 +71,7 @@ async fn request_identity_tokens( ) -> Result { use crate::DeviceType; - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); PasswordTokenRequest::new( &input.email, password_hash, diff --git a/crates/bitwarden-core/src/auth/login/two_factor.rs b/crates/bitwarden-core/src/auth/login/two_factor.rs index c0a4c10ab..3ba340d09 100644 --- a/crates/bitwarden-core/src/auth/login/two_factor.rs +++ b/crates/bitwarden-core/src/auth/login/two_factor.rs @@ -29,7 +29,7 @@ pub(crate) async fn send_two_factor_email( HashPurpose::ServerAuthorization, )?; - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); bitwarden_api_api::apis::two_factor_api::two_factor_send_email_login_post( &config.api, Some(TwoFactorEmailRequestModel { diff --git a/crates/bitwarden-core/src/auth/password/validate.rs b/crates/bitwarden-core/src/auth/password/validate.rs index 3aeeef6ad..8aaa4eda2 100644 --- a/crates/bitwarden-core/src/auth/password/validate.rs +++ b/crates/bitwarden-core/src/auth/password/validate.rs @@ -23,8 +23,8 @@ pub(crate) fn validate_password( UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. } => { let hash = determine_password_hash( - &email, - &kdf, + email, + kdf, &password, HashPurpose::LocalAuthorization, )?; @@ -54,7 +54,7 @@ pub(crate) fn validate_password_user_key( match login_method { UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. } => { - let master_key = MasterKey::derive(password.as_bytes(), email.as_bytes(), &kdf)?; + let master_key = MasterKey::derive(password.as_bytes(), email.as_bytes(), kdf)?; let user_key = master_key .decrypt_user_key(encrypted_user_key.parse()?) .map_err(|_| "wrong password")?; diff --git a/crates/bitwarden-core/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs index cf0c36144..38437f737 100644 --- a/crates/bitwarden-core/src/auth/register.rs +++ b/crates/bitwarden-core/src/auth/register.rs @@ -19,7 +19,7 @@ pub struct RegisterRequest { /// Half baked implementation of user registration pub(super) async fn register(client: &Client, req: &RegisterRequest) -> Result<()> { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let kdf = Kdf::default(); diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index 3c4bda8b9..b02d81eba 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -145,7 +145,7 @@ impl InternalClient { } } - pub async fn get_api_configurations(&self) -> Arc { + pub 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(); diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index 3266a3420..ac7b4742b 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -1,57 +1,3 @@ -//! # Bitwarden -//! -//! A Rust client SDK to interact with the Bitwarden Secrets Manager. -//! This is a beta release and might be missing some functionality. -//! -//! To use this crate, add it to your `Cargo.toml`: -//! -//! ```ini -//! [dependencies] -//! bitwarden = { "*", features = ["secrets"] } -//! ``` -//! -//! # Basic setup -//! -//! All operations in this crate are done via a [Client]: -//! -//! ```rust -//! use bitwarden::{ -//! auth::login::AccessTokenLoginRequest, error::Result, -//! secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, -//! }; -//! use uuid::Uuid; -//! -//! async fn test() -> Result<()> { -//! // Use the default values -//! let mut client = Client::new(None); -//! -//! // Or set your own values -//! let settings = ClientSettings { -//! identity_url: "https://identity.bitwarden.com".to_string(), -//! api_url: "https://api.bitwarden.com".to_string(), -//! user_agent: "Bitwarden Rust-SDK".to_string(), -//! device_type: DeviceType::SDK, -//! }; -//! let mut client = Client::new(Some(settings)); -//! -//! // Before we operate, we need to authenticate with a token -//! let token = AccessTokenLoginRequest { -//! access_token: String::from(""), -//! state_file: None, -//! }; -//! client.auth().login_access_token(&token).await.unwrap(); -//! -//! let org_id = SecretIdentifiersRequest { -//! organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), -//! }; -//! println!( -//! "Stored secrets: {:#?}", -//! client.secrets().list(&org_id).await.unwrap() -//! ); -//! Ok(()) -//! } -//! ``` - // Ensure the readme docs compile #[doc = include_str!("../README.md")] mod readme {} diff --git a/crates/bitwarden-core/src/platform/get_user_api_key.rs b/crates/bitwarden-core/src/platform/get_user_api_key.rs index dcdafa0b4..5d5f84eda 100644 --- a/crates/bitwarden-core/src/platform/get_user_api_key.rs +++ b/crates/bitwarden-core/src/platform/get_user_api_key.rs @@ -26,7 +26,7 @@ pub(crate) async fn get_user_api_key( let auth_settings = get_login_method(client)?; let request = get_secret_verification_request(&auth_settings, input)?; - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let response = accounts_api_key_post(&config.api, Some(request)).await?; UserApiKeyResponse::process_response(response) diff --git a/crates/bitwarden-sm/src/projects/create.rs b/crates/bitwarden-sm/src/projects/create.rs index bacec3cef..e14a95335 100644 --- a/crates/bitwarden-sm/src/projects/create.rs +++ b/crates/bitwarden-sm/src/projects/create.rs @@ -29,7 +29,7 @@ pub(crate) async fn create_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_post( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs index 27e7f83e7..f569e3420 100644 --- a/crates/bitwarden-sm/src/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_projects( client: &Client, input: ProjectsDeleteRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::projects_api::projects_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs index 81a669739..bd2cce8eb 100644 --- a/crates/bitwarden-sm/src/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_project( client: &Client, input: &ProjectGetRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::projects_api::projects_id_get(&config.api, input.id).await?; diff --git a/crates/bitwarden-sm/src/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs index 334e06007..90df70bbe 100644 --- a/crates/bitwarden-sm/src/projects/list.rs +++ b/crates/bitwarden-sm/src/projects/list.rs @@ -20,7 +20,7 @@ pub(crate) async fn list_projects( client: &Client, input: &ProjectsListRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_get( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs index 759edff99..196058ef6 100644 --- a/crates/bitwarden-sm/src/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -31,7 +31,7 @@ pub(crate) async fn update_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::projects_api::projects_id_put(&config.api, input.id, project) .await?; diff --git a/crates/bitwarden-sm/src/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs index 3e83d390d..bff9ff012 100644 --- a/crates/bitwarden-sm/src/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -37,7 +37,7 @@ pub(crate) async fn create_secret( project_ids: input.project_ids.clone(), }); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_post( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs index 377d19f62..a2a44427f 100644 --- a/crates/bitwarden-sm/src/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_secrets( client: &Client, input: SecretsDeleteRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::secrets_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs index d0964df2e..b433bcb1d 100644 --- a/crates/bitwarden-sm/src/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_secret( client: &Client, input: &SecretGetRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::secrets_id_get(&config.api, input.id).await?; let enc = client.internal.get_encryption_settings()?; diff --git a/crates/bitwarden-sm/src/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs index b5714c4b7..471c9c98e 100644 --- a/crates/bitwarden-sm/src/secrets/get_by_ids.rs +++ b/crates/bitwarden-sm/src/secrets/get_by_ids.rs @@ -19,7 +19,7 @@ pub(crate) async fn get_secrets_by_ids( ) -> Result { let request = Some(GetSecretsRequestModel { ids: input.ids }); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::secrets_get_by_ids_post(&config.api, request).await?; diff --git a/crates/bitwarden-sm/src/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs index 9de4b9a47..749cf2c49 100644 --- a/crates/bitwarden-sm/src/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -21,7 +21,7 @@ pub(crate) async fn list_secrets( client: &Client, input: &SecretIdentifiersRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_get( &config.api, input.organization_id, @@ -44,7 +44,7 @@ pub(crate) async fn list_secrets_by_project( client: &Client, input: &SecretIdentifiersByProjectRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::projects_project_id_secrets_get( &config.api, input.project_id, diff --git a/crates/bitwarden-sm/src/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs index 9c922a002..07f275ceb 100644 --- a/crates/bitwarden-sm/src/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -20,7 +20,7 @@ pub(crate) async fn sync_secrets( client: &Client, input: &SecretsSyncRequest, ) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let last_synced_date = input.last_synced_date.map(|date| date.to_rfc3339()); let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_sync_get( diff --git a/crates/bitwarden-sm/src/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs index 00f1ed2a4..5342f74ba 100644 --- a/crates/bitwarden-sm/src/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -38,7 +38,7 @@ pub(crate) async fn update_secret( project_ids: input.project_ids.clone(), }); - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let res = bitwarden_api_api::apis::secrets_api::secrets_id_put(&config.api, input.id, secret).await?; diff --git a/crates/bitwarden-vault/src/sync.rs b/crates/bitwarden-vault/src/sync.rs index 6b4845d35..f60871d76 100644 --- a/crates/bitwarden-vault/src/sync.rs +++ b/crates/bitwarden-vault/src/sync.rs @@ -31,7 +31,7 @@ pub struct SyncRequest { } pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result { - let config = client.internal.get_api_configurations().await; + let config = client.internal.get_api_configurations(); let sync = bitwarden_api_api::apis::sync_api::sync_get(&config.api, input.exclude_subdomains) .await .map_err(|e| SyncError::Core(e.into()))?; From da2e0dd6ce65b9a58604a31a711b2e0999f070ca Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 14:04:15 +0200 Subject: [PATCH 13/28] Cleanup readmes --- crates/bitwarden-core/README.md | 58 ++---------------- crates/bitwarden-core/src/lib.rs | 4 -- .../src/client_exporter.rs | 2 +- crates/bitwarden-uniffi/src/platform/mod.rs | 7 +-- crates/bitwarden/README.md | 56 +++++++++++++++++ crates/bitwarden/src/error.rs | 1 - crates/bitwarden/src/lib.rs | 58 ++++++++++++++++++ crates/bitwarden/test.sqlite | Bin 12288 -> 0 bytes 8 files changed, 120 insertions(+), 66 deletions(-) create mode 100644 crates/bitwarden/README.md delete mode 100644 crates/bitwarden/test.sqlite diff --git a/crates/bitwarden-core/README.md b/crates/bitwarden-core/README.md index ed0139a65..baddb938e 100644 --- a/crates/bitwarden-core/README.md +++ b/crates/bitwarden-core/README.md @@ -1,56 +1,6 @@ -# Bitwarden Secrets Manager SDK +# Bitwarden Core -A Rust client SDK to interact with the -[Bitwarden Secrets Manager](https://bitwarden.com/products/secrets-manager/). This is a beta release -and might be missing some functionality. +This is an internal crate for the Bitwarden SDK do not depend on this directly and use the +[`bitwarden`](https://crates.io/crates/bitwarden) crate instead. -## Usage - -```toml -[dependencies] -bitwarden = { "*", features = ["secrets"] } -``` - -## Minimum Supported Rust Version - -Rust **1.71** or higher. - -## Example - -```rust -use bitwarden::{ - auth::login::AccessTokenLoginRequest, error::Result, - secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, -}; -use uuid::Uuid; - -async fn test() -> Result<()> { - // Use the default values - let mut client = Client::new(None); - - // Or set your own values - let settings = ClientSettings { - identity_url: "https://identity.bitwarden.com".to_string(), - api_url: "https://api.bitwarden.com".to_string(), - user_agent: "Bitwarden Rust-SDK".to_string(), - device_type: DeviceType::SDK, - }; - let mut client = Client::new(Some(settings)); - - // Before we operate, we need to authenticate with a token - let token = AccessTokenLoginRequest { - access_token: String::from(""), - state_file: None, - }; - client.auth().login_access_token(&token).await.unwrap(); - - let org_id = SecretIdentifiersRequest { - organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), - }; - println!( - "Stored secrets: {:#?}", - client.secrets().list(&org_id).await.unwrap() - ); - Ok(()) -} -``` +This crate does not follow semantic versioning and the public interface may change at any time. diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index ac7b4742b..409f0133b 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -1,7 +1,3 @@ -// Ensure the readme docs compile -#[doc = include_str!("../README.md")] -mod readme {} - #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); #[cfg(feature = "uniffi")] diff --git a/crates/bitwarden-exporters/src/client_exporter.rs b/crates/bitwarden-exporters/src/client_exporter.rs index 6d7a12f13..ffc9963c1 100644 --- a/crates/bitwarden-exporters/src/client_exporter.rs +++ b/crates/bitwarden-exporters/src/client_exporter.rs @@ -21,7 +21,7 @@ impl<'a> ClientExporters<'a> { ciphers: Vec, format: ExportFormat, ) -> Result { - export_vault(&self.client, folders, ciphers, format) + export_vault(self.client, folders, ciphers, format) } pub fn export_organization_vault( diff --git a/crates/bitwarden-uniffi/src/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index e3d3aa644..594b38908 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -26,13 +26,8 @@ impl ClientPlatform { } /// Load feature flags into the client - pub async fn load_flags(&self, flags: std::collections::HashMap) -> Result<()> { + pub fn load_flags(&self, flags: std::collections::HashMap) -> Result<()> { self.0 .0.internal.load_flags(flags); Ok(()) } - - // /// FIDO2 operations - //pub fn fido2(self: Arc) -> Arc { - // Arc::new(fido2::ClientFido2(self.0.clone())) - //} } diff --git a/crates/bitwarden/README.md b/crates/bitwarden/README.md new file mode 100644 index 000000000..ed0139a65 --- /dev/null +++ b/crates/bitwarden/README.md @@ -0,0 +1,56 @@ +# Bitwarden Secrets Manager SDK + +A Rust client SDK to interact with the +[Bitwarden Secrets Manager](https://bitwarden.com/products/secrets-manager/). This is a beta release +and might be missing some functionality. + +## Usage + +```toml +[dependencies] +bitwarden = { "*", features = ["secrets"] } +``` + +## Minimum Supported Rust Version + +Rust **1.71** or higher. + +## Example + +```rust +use bitwarden::{ + auth::login::AccessTokenLoginRequest, error::Result, + secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, +}; +use uuid::Uuid; + +async fn test() -> Result<()> { + // Use the default values + let mut client = Client::new(None); + + // Or set your own values + let settings = ClientSettings { + identity_url: "https://identity.bitwarden.com".to_string(), + api_url: "https://api.bitwarden.com".to_string(), + user_agent: "Bitwarden Rust-SDK".to_string(), + device_type: DeviceType::SDK, + }; + let mut client = Client::new(Some(settings)); + + // Before we operate, we need to authenticate with a token + let token = AccessTokenLoginRequest { + access_token: String::from(""), + state_file: None, + }; + client.auth().login_access_token(&token).await.unwrap(); + + let org_id = SecretIdentifiersRequest { + organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), + }; + println!( + "Stored secrets: {:#?}", + client.secrets().list(&org_id).await.unwrap() + ); + Ok(()) +} +``` diff --git a/crates/bitwarden/src/error.rs b/crates/bitwarden/src/error.rs index e8278ad6c..ae384b35c 100644 --- a/crates/bitwarden/src/error.rs +++ b/crates/bitwarden/src/error.rs @@ -6,7 +6,6 @@ use std::{borrow::Cow, fmt::Debug}; use bitwarden_exporters::ExportError; #[cfg(feature = "internal")] use bitwarden_generators::{PassphraseError, PasswordError, UsernameError}; -use reqwest::StatusCode; use thiserror::Error; #[derive(Debug, Error)] diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index 55d8bad6a..676caba1a 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -1,3 +1,61 @@ +//! # Bitwarden +//! +//! A Rust client SDK to interact with the Bitwarden Secrets Manager. +//! This is a beta release and might be missing some functionality. +//! +//! To use this crate, add it to your `Cargo.toml`: +//! +//! ```ini +//! [dependencies] +//! bitwarden = { "*", features = ["secrets"] } +//! ``` +//! +//! # Basic setup +//! +//! All operations in this crate are done via a [Client]: +//! +//! ```rust +//! use bitwarden::{ +//! auth::login::AccessTokenLoginRequest, error::Result, +//! secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, +//! }; +//! use uuid::Uuid; +//! +//! async fn test() -> Result<()> { +//! // Use the default values +//! let mut client = Client::new(None); +//! +//! // Or set your own values +//! let settings = ClientSettings { +//! identity_url: "https://identity.bitwarden.com".to_string(), +//! api_url: "https://api.bitwarden.com".to_string(), +//! user_agent: "Bitwarden Rust-SDK".to_string(), +//! device_type: DeviceType::SDK, +//! }; +//! let mut client = Client::new(Some(settings)); +//! +//! // Before we operate, we need to authenticate with a token +//! let token = AccessTokenLoginRequest { +//! access_token: String::from(""), +//! state_file: None, +//! }; +//! client.auth().login_access_token(&token).await.unwrap(); +//! +//! let org_id = SecretIdentifiersRequest { +//! organization_id: Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(), +//! }; +//! println!( +//! "Stored secrets: {:#?}", +//! client.secrets().list(&org_id).await.unwrap() +//! ); +//! Ok(()) +//! } +//! ``` + +// Ensure the readme docs compile +#[doc = include_str!("../README.md")] +mod readme {} + pub use bitwarden_core::*; pub mod error; diff --git a/crates/bitwarden/test.sqlite b/crates/bitwarden/test.sqlite deleted file mode 100644 index 741c5fdc34b49bffd36fb78d5ded23b3113e44e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI$&raJg7y$4D(EcEyPU3(xE>TXKNFYg@0+o;`qZ-f>C<}*F?EyRIBnV3 zVG@Tuz#d@_Flo2lcHEAWrfKi62iS2g{lnOSUAO78VkM40`?G)P#oaBJ2**k-WKG1C zv~*9BWocPaBuSbSbyUmT>=*y z@|gDO?8_nk`T;G!dHw0_XZhmW{pTw2)tu_vwx6~AdEGO!rk*iSMqkW$NUs{cWta;Y zf6+v$riQGJ0`d%T5(evHT#!(zskM;$m|eBKkcyLRFD6!VPY*SOr+JM8{e}**@^N?L_fZ@xpBj&nP zHmrd=hE3((>9(69UoK7vEK{q88O@ Date: Mon, 17 Jun 2024 14:19:56 +0200 Subject: [PATCH 14/28] Simplify errors --- crates/bitwarden-core/src/error.rs | 20 ------------------- crates/bitwarden-uniffi/src/error.rs | 21 +++----------------- crates/bitwarden-uniffi/src/lib.rs | 3 +-- crates/bitwarden-uniffi/src/platform/mod.rs | 5 +++++ crates/bitwarden-uniffi/src/tool/mod.rs | 19 +++++++++--------- crates/bitwarden-uniffi/src/vault/ciphers.rs | 9 ++++++--- crates/bitwarden-uniffi/src/vault/mod.rs | 12 +++++------ crates/bitwarden/src/error.rs | 15 +++----------- 8 files changed, 33 insertions(+), 71 deletions(-) diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index 2cfee4a61..5e7f4338a 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -4,8 +4,6 @@ use std::{borrow::Cow, fmt::Debug}; use bitwarden_api_api::apis::Error as ApiError; use bitwarden_api_identity::apis::Error as IdentityError; -#[cfg(feature = "uniffi")] -use passkey::client::WebauthnError; use reqwest::StatusCode; use thiserror::Error; @@ -51,28 +49,10 @@ pub enum Error { #[error("The state file could not be read")] InvalidStateFile, - #[cfg(feature = "uniffi")] - #[error("Webauthn error: {0:?}")] - WebauthnError(WebauthnError), - - #[cfg(feature = "uniffi")] - #[error("Uniffi callback error: {0}")] - UniffiCallbackError(#[from] uniffi::UnexpectedUniFFICallbackError), - - //#[cfg(feature = "uniffi")] - //#[error("Fido2 Callback error: {0:?}")] - //Fido2CallbackError(#[from] crate::platform::fido2::Fido2CallbackError), #[error("Internal error: {0}")] Internal(Cow<'static, str>), } -#[cfg(feature = "uniffi")] -impl From for Error { - fn from(e: WebauthnError) -> Self { - Self::WebauthnError(e) - } -} - impl From for Error { fn from(s: String) -> Self { Self::Internal(s.into()) diff --git a/crates/bitwarden-uniffi/src/error.rs b/crates/bitwarden-uniffi/src/error.rs index cb854b498..5a1dfe43a 100644 --- a/crates/bitwarden-uniffi/src/error.rs +++ b/crates/bitwarden-uniffi/src/error.rs @@ -5,27 +5,18 @@ use std::fmt::{Display, Formatter}; #[derive(uniffi::Error, Debug)] #[uniffi(flat_error)] pub enum BitwardenError { - E(bitwarden::Error), - E2(bitwarden::error::Error), - Ee(bitwarden::exporters::ExportError), - Totp(bitwarden::vault::TotpError), + E(bitwarden::error::Error), } impl From for BitwardenError { fn from(e: bitwarden::Error) -> Self { - Self::E(e) + Self::E(e.into()) } } impl From for BitwardenError { fn from(e: bitwarden::error::Error) -> Self { - Self::E2(e) - } -} - -impl From for BitwardenError { - fn from(e: bitwarden::exporters::ExportError) -> Self { - Self::Ee(e) + Self::E(e) } } @@ -33,9 +24,6 @@ impl Display for BitwardenError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::E(e) => Display::fmt(e, f), - Self::E2(e) => Display::fmt(e, f), - Self::Ee(e) => Display::fmt(e, f), - Self::Totp(e) => Display::fmt(e, f), } } } @@ -44,9 +32,6 @@ impl std::error::Error for BitwardenError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { BitwardenError::E(e) => Some(e), - BitwardenError::E2(e) => Some(e), - BitwardenError::Ee(e) => Some(e), - BitwardenError::Totp(e) => Some(e), } } } diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index eb71f0bbf..d8e3a8c73 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -18,6 +18,7 @@ pub mod docs; use crypto::ClientCrypto; use error::Result; +use platform::ClientPlatform; //use platform::ClientPlatform; use tool::{ClientExporters, ClientGenerators, ClientSends}; use vault::ClientVault; @@ -44,11 +45,9 @@ impl Client { Arc::new(ClientVault(self)) } - /* pub fn platform(self: Arc) -> Arc { Arc::new(ClientPlatform(self)) } - */ /// Generator operations pub fn generators(self: Arc) -> Arc { diff --git a/crates/bitwarden-uniffi/src/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index 594b38908..63ff6e183 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -30,4 +30,9 @@ impl ClientPlatform { self.0 .0.internal.load_flags(flags); Ok(()) } + + /// FIDO2 operations + pub fn fido2(self: Arc) -> Arc { + Arc::new(fido2::ClientFido2(self.0.clone())) + } } diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index 9fc814740..1fd439a4f 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -1,19 +1,16 @@ use std::sync::Arc; use bitwarden::{ + error::Error, exporters::{ClientExportersExt, ExportFormat}, generators::{ ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, }, vault::{Cipher, Collection, Folder}, - Error, VaultLocked, }; -use crate::{ - error::{BitwardenError, Result}, - Client, -}; +use crate::{error::Result, Client}; mod sends; pub use sends::ClientSends; @@ -30,7 +27,7 @@ impl ClientGenerators { .0 .generator() .password(settings) - .map_err(|_| Error::VaultLocked(VaultLocked))?) + .map_err(Error::PasswordError)?) } /// **API Draft:** Generate Passphrase @@ -40,7 +37,7 @@ impl ClientGenerators { .0 .generator() .passphrase(settings) - .map_err(|_| Error::VaultLocked(VaultLocked))?) + .map_err(Error::PassphraseError)?) } /// **API Draft:** Generate Username @@ -51,7 +48,7 @@ impl ClientGenerators { .generator() .username(settings) .await - .map_err(|_| BitwardenError::E2(bitwarden::error::Error::VaultLocked(VaultLocked)))?) + .map_err(Error::UsernameError)?) } } @@ -71,7 +68,8 @@ impl ClientExporters { .0 .0 .exporters() - .export_vault(folders, ciphers, format)?) + .export_vault(folders, ciphers, format) + .map_err(Error::ExportError)?) } /// **API Draft:** Export organization vault @@ -85,6 +83,7 @@ impl ClientExporters { .0 .0 .exporters() - .export_organization_vault(collections, ciphers, format)?) + .export_organization_vault(collections, ciphers, format) + .map_err(Error::ExportError)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/ciphers.rs b/crates/bitwarden-uniffi/src/vault/ciphers.rs index 790de4c3b..1195cf81a 100644 --- a/crates/bitwarden-uniffi/src/vault/ciphers.rs +++ b/crates/bitwarden-uniffi/src/vault/ciphers.rs @@ -1,10 +1,13 @@ use std::sync::Arc; -use bitwarden::vault::{Cipher, CipherListView, CipherView, ClientVaultExt}; +use bitwarden::{ + error::Error, + vault::{Cipher, CipherListView, CipherView, ClientVaultExt}, +}; use bitwarden_vault::Fido2CredentialView; use uuid::Uuid; -use crate::{error::BitwardenError, Client, Result}; +use crate::{Client, Result}; #[derive(uniffi::Object)] pub struct ClientCiphers(pub Arc); @@ -50,6 +53,6 @@ impl ClientCiphers { .vault() .ciphers() .move_to_organization(cipher, organization_id) - .map_err(|e| BitwardenError::E2(bitwarden::error::Error::Cipher(e)))?) + .map_err(Error::Cipher)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/mod.rs b/crates/bitwarden-uniffi/src/vault/mod.rs index 77476b0d2..5f4e80707 100644 --- a/crates/bitwarden-uniffi/src/vault/mod.rs +++ b/crates/bitwarden-uniffi/src/vault/mod.rs @@ -1,12 +1,12 @@ use std::sync::Arc; -use bitwarden::vault::{ClientVaultExt, TotpResponse}; +use bitwarden::{ + error::Error, + vault::{ClientVaultExt, TotpResponse}, +}; use chrono::{DateTime, Utc}; -use crate::{ - error::{BitwardenError, Result}, - Client, -}; +use crate::{error::Result, Client}; pub mod attachments; pub mod ciphers; @@ -56,6 +56,6 @@ impl ClientVault { .0 .vault() .generate_totp(key, time) - .map_err(BitwardenError::Totp)?) + .map_err(Error::Totp)?) } } diff --git a/crates/bitwarden/src/error.rs b/crates/bitwarden/src/error.rs index ae384b35c..ba5edd798 100644 --- a/crates/bitwarden/src/error.rs +++ b/crates/bitwarden/src/error.rs @@ -10,26 +10,17 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum Error { + #[error(transparent)] + Core(#[from] bitwarden_core::Error), + #[error(transparent)] MissingFieldError(#[from] bitwarden_core::MissingFieldError), #[error(transparent)] VaultLocked(#[from] bitwarden_core::VaultLocked), - #[error("The client is not authenticated or the session has expired")] - NotAuthenticated, - - #[error("The response received was invalid and could not be processed")] - InvalidResponse, - #[error("Cryptography error, {0}")] Crypto(#[from] bitwarden_crypto::CryptoError), - #[error("The state file version is invalid")] - InvalidStateFileVersion, - - #[error("The state file could not be read")] - InvalidStateFile, - // Generators #[cfg(feature = "internal")] #[error(transparent)] From 214cad362c696d71cedbbe1dd0c20505442bbc14 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 14:21:31 +0200 Subject: [PATCH 15/28] Remove comment --- crates/bitwarden-uniffi/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bitwarden-uniffi/src/lib.rs b/crates/bitwarden-uniffi/src/lib.rs index d8e3a8c73..6ef7e6cf4 100644 --- a/crates/bitwarden-uniffi/src/lib.rs +++ b/crates/bitwarden-uniffi/src/lib.rs @@ -19,7 +19,6 @@ pub mod docs; use crypto::ClientCrypto; use error::Result; use platform::ClientPlatform; -//use platform::ClientPlatform; use tool::{ClientExporters, ClientGenerators, ClientSends}; use vault::ClientVault; From 4336a0ab0e68d52c9a4739486752dfcbb7501c01 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 14:42:23 +0200 Subject: [PATCH 16/28] Bring back async for get_api_configurations --- .../src/auth/login/access_token.rs | 2 +- .../bitwarden-core/src/auth/login/api_key.rs | 2 +- .../src/auth/login/auth_request.rs | 4 +- crates/bitwarden-core/src/auth/login/mod.rs | 2 +- .../bitwarden-core/src/auth/login/password.rs | 2 +- .../src/auth/login/two_factor.rs | 2 +- crates/bitwarden-core/src/auth/register.rs | 2 +- crates/bitwarden-core/src/client/internal.rs | 6 +- .../src/platform/get_user_api_key.rs | 2 +- crates/bitwarden-send/src/lib.rs | 5 +- crates/bitwarden-sm/src/projects/create.rs | 2 +- crates/bitwarden-sm/src/projects/delete.rs | 2 +- crates/bitwarden-sm/src/projects/get.rs | 2 +- crates/bitwarden-sm/src/projects/list.rs | 2 +- crates/bitwarden-sm/src/projects/update.rs | 2 +- crates/bitwarden-sm/src/secrets/create.rs | 2 +- crates/bitwarden-sm/src/secrets/delete.rs | 2 +- crates/bitwarden-sm/src/secrets/get.rs | 2 +- crates/bitwarden-sm/src/secrets/get_by_ids.rs | 2 +- crates/bitwarden-sm/src/secrets/list.rs | 4 +- crates/bitwarden-sm/src/secrets/sync.rs | 2 +- crates/bitwarden-sm/src/secrets/update.rs | 2 +- crates/bitwarden-vault/src/sync.rs | 2 +- crates/bitwarden/src/client/client.rs | 355 ------------------ 24 files changed, 28 insertions(+), 384 deletions(-) delete mode 100644 crates/bitwarden/src/client/client.rs diff --git a/crates/bitwarden-core/src/auth/login/access_token.rs b/crates/bitwarden-core/src/auth/login/access_token.rs index 0b16a6515..c445e43c7 100644 --- a/crates/bitwarden-core/src/auth/login/access_token.rs +++ b/crates/bitwarden-core/src/auth/login/access_token.rs @@ -106,7 +106,7 @@ async fn request_access_token( client: &Client, input: &AccessToken, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; AccessTokenRequest::new(input.access_token_id, &input.client_secret) .send(&config) .await diff --git a/crates/bitwarden-core/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs index 089a0e1c3..b0e2c8834 100644 --- a/crates/bitwarden-core/src/auth/login/api_key.rs +++ b/crates/bitwarden-core/src/auth/login/api_key.rs @@ -64,7 +64,7 @@ async fn request_api_identity_tokens( client: &Client, input: &ApiKeyLoginRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; ApiTokenRequest::new(&input.client_id, &input.client_secret) .send(&config) .await diff --git a/crates/bitwarden-core/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs index 0501a124f..912105db0 100644 --- a/crates/bitwarden-core/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -30,7 +30,7 @@ pub(crate) async fn send_new_auth_request( email: String, device_identifier: String, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let auth = new_auth_request(&email)?; @@ -58,7 +58,7 @@ pub(crate) async fn complete_auth_request( client: &Client, auth_req: NewAuthRequestResponse, ) -> Result<()> { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = auth_requests_id_response_get( &config.api, diff --git a/crates/bitwarden-core/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs index fac318df1..04c2804b6 100644 --- a/crates/bitwarden-core/src/auth/login/mod.rs +++ b/crates/bitwarden-core/src/auth/login/mod.rs @@ -49,7 +49,7 @@ pub(crate) async fn request_prelogin( email: String, ) -> Result { let request_model = PreloginRequestModel::new(email); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; Ok(accounts_prelogin_post(&config.identity, Some(request_model)).await?) } diff --git a/crates/bitwarden-core/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs index ed93fede9..c5d32bdaf 100644 --- a/crates/bitwarden-core/src/auth/login/password.rs +++ b/crates/bitwarden-core/src/auth/login/password.rs @@ -71,7 +71,7 @@ async fn request_identity_tokens( ) -> Result { use crate::DeviceType; - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; PasswordTokenRequest::new( &input.email, password_hash, diff --git a/crates/bitwarden-core/src/auth/login/two_factor.rs b/crates/bitwarden-core/src/auth/login/two_factor.rs index 3ba340d09..c0a4c10ab 100644 --- a/crates/bitwarden-core/src/auth/login/two_factor.rs +++ b/crates/bitwarden-core/src/auth/login/two_factor.rs @@ -29,7 +29,7 @@ pub(crate) async fn send_two_factor_email( HashPurpose::ServerAuthorization, )?; - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; bitwarden_api_api::apis::two_factor_api::two_factor_send_email_login_post( &config.api, Some(TwoFactorEmailRequestModel { diff --git a/crates/bitwarden-core/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs index 38437f737..cf0c36144 100644 --- a/crates/bitwarden-core/src/auth/register.rs +++ b/crates/bitwarden-core/src/auth/register.rs @@ -19,7 +19,7 @@ pub struct RegisterRequest { /// Half baked implementation of user registration pub(super) async fn register(client: &Client, req: &RegisterRequest) -> Result<()> { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let kdf = Kdf::default(); diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index b02d81eba..51aa775fb 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -42,7 +42,7 @@ pub struct InternalClient { #[cfg(feature = "internal")] pub(super) flags: RwLock, - /// Use Client::get_api_configurations() to access this. + /// Use Client::get_api_configurations().await to access this. /// It should only be used directly in renew_token #[doc(hidden)] pub(crate) __api_configurations: RwLock>, @@ -145,10 +145,10 @@ impl InternalClient { } } - pub fn get_api_configurations(&self) -> Arc { + pub 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.auth().renew_token().await.ok(); self.__api_configurations .read() .expect("RwLock is not poisoned") diff --git a/crates/bitwarden-core/src/platform/get_user_api_key.rs b/crates/bitwarden-core/src/platform/get_user_api_key.rs index 5d5f84eda..dcdafa0b4 100644 --- a/crates/bitwarden-core/src/platform/get_user_api_key.rs +++ b/crates/bitwarden-core/src/platform/get_user_api_key.rs @@ -26,7 +26,7 @@ pub(crate) async fn get_user_api_key( let auth_settings = get_login_method(client)?; let request = get_secret_verification_request(&auth_settings, input)?; - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let response = accounts_api_key_post(&config.api, Some(request)).await?; UserApiKeyResponse::process_response(response) diff --git a/crates/bitwarden-send/src/lib.rs b/crates/bitwarden-send/src/lib.rs index be274fcab..e29d7305f 100644 --- a/crates/bitwarden-send/src/lib.rs +++ b/crates/bitwarden-send/src/lib.rs @@ -1,5 +1,7 @@ #[cfg(feature = "uniffi")] uniffi::setup_scaffolding!(); +#[cfg(feature = "uniffi")] +mod uniffi_support; mod error; pub use error::SendParseError; @@ -7,6 +9,3 @@ mod client_sends; pub use client_sends::{ClientSends, ClientSendsExt}; mod send; pub use send::{Send, SendListView, SendView}; - -#[cfg(feature = "uniffi")] -mod uniffi_support; diff --git a/crates/bitwarden-sm/src/projects/create.rs b/crates/bitwarden-sm/src/projects/create.rs index e14a95335..bacec3cef 100644 --- a/crates/bitwarden-sm/src/projects/create.rs +++ b/crates/bitwarden-sm/src/projects/create.rs @@ -29,7 +29,7 @@ pub(crate) async fn create_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_post( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs index f569e3420..27e7f83e7 100644 --- a/crates/bitwarden-sm/src/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_projects( client: &Client, input: ProjectsDeleteRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs index bd2cce8eb..81a669739 100644 --- a/crates/bitwarden-sm/src/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_project( client: &Client, input: &ProjectGetRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_id_get(&config.api, input.id).await?; diff --git a/crates/bitwarden-sm/src/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs index 90df70bbe..334e06007 100644 --- a/crates/bitwarden-sm/src/projects/list.rs +++ b/crates/bitwarden-sm/src/projects/list.rs @@ -20,7 +20,7 @@ pub(crate) async fn list_projects( client: &Client, input: &ProjectsListRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::organizations_organization_id_projects_get( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs index 196058ef6..759edff99 100644 --- a/crates/bitwarden-sm/src/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -31,7 +31,7 @@ pub(crate) async fn update_project( name: input.name.clone().encrypt_with_key(key)?.to_string(), }); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::projects_api::projects_id_put(&config.api, input.id, project) .await?; diff --git a/crates/bitwarden-sm/src/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs index bff9ff012..3e83d390d 100644 --- a/crates/bitwarden-sm/src/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -37,7 +37,7 @@ pub(crate) async fn create_secret( project_ids: input.project_ids.clone(), }); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_post( &config.api, input.organization_id, diff --git a/crates/bitwarden-sm/src/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs index a2a44427f..377d19f62 100644 --- a/crates/bitwarden-sm/src/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -17,7 +17,7 @@ pub(crate) async fn delete_secrets( client: &Client, input: SecretsDeleteRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_delete_post(&config.api, Some(input.ids)) .await?; diff --git a/crates/bitwarden-sm/src/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs index b433bcb1d..d0964df2e 100644 --- a/crates/bitwarden-sm/src/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -16,7 +16,7 @@ pub(crate) async fn get_secret( client: &Client, input: &SecretGetRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_id_get(&config.api, input.id).await?; let enc = client.internal.get_encryption_settings()?; diff --git a/crates/bitwarden-sm/src/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs index 471c9c98e..b5714c4b7 100644 --- a/crates/bitwarden-sm/src/secrets/get_by_ids.rs +++ b/crates/bitwarden-sm/src/secrets/get_by_ids.rs @@ -19,7 +19,7 @@ pub(crate) async fn get_secrets_by_ids( ) -> Result { let request = Some(GetSecretsRequestModel { ids: input.ids }); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_get_by_ids_post(&config.api, request).await?; diff --git a/crates/bitwarden-sm/src/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs index 749cf2c49..9de4b9a47 100644 --- a/crates/bitwarden-sm/src/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -21,7 +21,7 @@ pub(crate) async fn list_secrets( client: &Client, input: &SecretIdentifiersRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_get( &config.api, input.organization_id, @@ -44,7 +44,7 @@ pub(crate) async fn list_secrets_by_project( client: &Client, input: &SecretIdentifiersByProjectRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::projects_project_id_secrets_get( &config.api, input.project_id, diff --git a/crates/bitwarden-sm/src/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs index 07f275ceb..9c922a002 100644 --- a/crates/bitwarden-sm/src/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -20,7 +20,7 @@ pub(crate) async fn sync_secrets( client: &Client, input: &SecretsSyncRequest, ) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let last_synced_date = input.last_synced_date.map(|date| date.to_rfc3339()); let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_sync_get( diff --git a/crates/bitwarden-sm/src/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs index 5342f74ba..00f1ed2a4 100644 --- a/crates/bitwarden-sm/src/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -38,7 +38,7 @@ pub(crate) async fn update_secret( project_ids: input.project_ids.clone(), }); - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let res = bitwarden_api_api::apis::secrets_api::secrets_id_put(&config.api, input.id, secret).await?; diff --git a/crates/bitwarden-vault/src/sync.rs b/crates/bitwarden-vault/src/sync.rs index f60871d76..6b4845d35 100644 --- a/crates/bitwarden-vault/src/sync.rs +++ b/crates/bitwarden-vault/src/sync.rs @@ -31,7 +31,7 @@ pub struct SyncRequest { } pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result { - let config = client.internal.get_api_configurations(); + let config = client.internal.get_api_configurations().await; let sync = bitwarden_api_api::apis::sync_api::sync_get(&config.api, input.exclude_subdomains) .await .map_err(|e| SyncError::Core(e.into()))?; diff --git a/crates/bitwarden/src/client/client.rs b/crates/bitwarden/src/client/client.rs deleted file mode 100644 index 413e704aa..000000000 --- a/crates/bitwarden/src/client/client.rs +++ /dev/null @@ -1,355 +0,0 @@ -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, -}; - -use bitwarden_core::VaultLocked; -#[cfg(feature = "internal")] -pub use bitwarden_crypto::Kdf; -use bitwarden_crypto::SymmetricCryptoKey; -#[cfg(feature = "internal")] -use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey}; -use chrono::Utc; -use reqwest::header::{self, HeaderValue}; -use uuid::Uuid; - -#[cfg(feature = "internal")] -use crate::client::flags::Flags; -use crate::{ - auth::AccessToken, client::encryption_settings::EncryptionSettings, error::Result, - ClientSettings, DeviceType, -}; - -#[derive(Debug, Clone)] -pub(crate) struct ApiConfigurations { - pub identity: bitwarden_api_identity::apis::configuration::Configuration, - pub api: bitwarden_api_api::apis::configuration::Configuration, - pub device_type: DeviceType, -} - -#[derive(Debug)] -pub(crate) enum LoginMethod { - #[cfg(feature = "internal")] - User(UserLoginMethod), - // TODO: Organizations supports api key - // Organization(OrganizationLoginMethod), - ServiceAccount(ServiceAccountLoginMethod), -} - -#[derive(Debug)] -#[cfg(feature = "internal")] -pub(crate) enum UserLoginMethod { - Username { - client_id: String, - email: String, - kdf: Kdf, - }, - ApiKey { - client_id: String, - client_secret: String, - - email: String, - kdf: Kdf, - }, -} - -#[derive(Debug)] -pub(crate) enum ServiceAccountLoginMethod { - AccessToken { - access_token: AccessToken, - organization_id: Uuid, - state_file: Option, - }, -} - -#[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 { - pub(crate) tokens: RwLock, - pub(crate) login_method: RwLock>>, - - #[cfg(feature = "internal")] - 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: RwLock>, - - /// Reqwest client useable for external integrations like email forwarders, HIBP. - #[allow(unused)] - pub(crate) external_client: reqwest::Client, - - encryption_settings: RwLock>>, -} - -impl Client { - pub fn new(settings_input: Option) -> Self { - let settings = settings_input.unwrap_or_default(); - - fn new_client_builder() -> reqwest::ClientBuilder { - #[allow(unused_mut)] - let mut client_builder = reqwest::Client::builder(); - - #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] - { - client_builder = - client_builder.use_preconfigured_tls(rustls_platform_verifier::tls_config()); - } - - client_builder - } - - let external_client = new_client_builder().build().expect("Build should not fail"); - - let mut headers = header::HeaderMap::new(); - headers.append( - "Device-Type", - HeaderValue::from_str(&(settings.device_type as u8).to_string()) - .expect("All numbers are valid ASCII"), - ); - let client_builder = new_client_builder().default_headers(headers); - - let client = client_builder.build().expect("Build should not fail"); - - let identity = bitwarden_api_identity::apis::configuration::Configuration { - base_path: settings.identity_url, - user_agent: Some(settings.user_agent.clone()), - client: client.clone(), - basic_auth: None, - oauth_access_token: None, - bearer_access_token: None, - api_key: None, - }; - - let api = bitwarden_api_api::apis::configuration::Configuration { - base_path: settings.api_url, - user_agent: Some(settings.user_agent), - client, - basic_auth: None, - oauth_access_token: None, - bearer_access_token: None, - api_key: None, - }; - - Self { - tokens: RwLock::new(Tokens::default()), - login_method: RwLock::new(None), - #[cfg(feature = "internal")] - flags: RwLock::new(Flags::default()), - __api_configurations: RwLock::new(Arc::new(ApiConfigurations { - identity, - api, - device_type: settings.device_type, - })), - external_client, - encryption_settings: RwLock::new(None), - } - } - - #[cfg(feature = "internal")] - 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.read().expect("RwLock is not poisoned").clone() - } - - 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 - .read() - .expect("RwLock is not poisoned") - .clone() - } - - #[cfg(feature = "internal")] - pub(crate) fn get_http_client(&self) -> &reqwest::Client { - &self.external_client - } - - #[cfg(feature = "internal")] - 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 - .read() - .expect("RwLock is not poisoned") - .as_deref() - { - Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { - organization_id, - .. - })) => Some(*organization_id), - _ => None, - } - } - - 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(&self, login_method: LoginMethod) { - use log::debug; - - debug! {"setting login method: {:#?}", login_method} - *self.login_method.write().expect("RwLock is not poisoned") = Some(Arc::new(login_method)); - } - - pub(crate) fn set_tokens(&self, token: String, refresh_token: Option, expires_in: u64) { - *self.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); - } - - pub fn is_authed(&self) -> bool { - 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( - &self, - master_key: MasterKey, - user_key: EncString, - private_key: EncString, - ) -> 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( - &self, - user_key: SymmetricCryptoKey, - private_key: EncString, - ) -> Result<()> { - *self - .encryption_settings - .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( - &self, - pin_key: MasterKey, - pin_protected_user_key: EncString, - private_key: EncString, - ) -> Result<()> { - let decrypted_user_key = pin_key.decrypt_user_key(pin_protected_user_key)?; - self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key) - } - - pub(crate) fn initialize_crypto_single_key(&self, key: SymmetricCryptoKey) { - *self - .encryption_settings - .write() - .expect("RwLock is not poisoned") = - Some(Arc::new(EncryptionSettings::new_single_key(key))); - } - - #[cfg(feature = "internal")] - pub(crate) fn initialize_org_crypto( - &self, - org_keys: Vec<(Uuid, AsymmetricEncString)>, - ) -> Result> { - 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)?; - let enc = Arc::new(enc); - - *guard = Some(enc.clone()); - - Ok(enc) - } -} - -#[cfg(test)] -mod tests { - #[test] - fn test_reqwest_rustls_platform_verifier_are_compatible() { - // rustls-platform-verifier is generating a rustls::ClientConfig, - // which reqwest accepts as a &dyn Any and then downcasts it to a - // rustls::ClientConfig. - - // This means that if the rustls version of the two crates don't match, - // the downcast will fail and we will get a runtime error. - - // This tests is added to ensure that it doesn't happen. - - let _ = reqwest::ClientBuilder::new() - .use_preconfigured_tls(rustls_platform_verifier::tls_config()) - .build() - .unwrap(); - } -} From 5b4487e4ef5077c54d12292a2726045dc477ddf1 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 17 Jun 2024 14:47:08 +0200 Subject: [PATCH 17/28] Fix renew token --- crates/bitwarden-core/src/auth/client_auth.rs | 2 +- crates/bitwarden-core/src/auth/renew.rs | 27 ++++++------------- crates/bitwarden-core/src/client/internal.rs | 3 ++- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/crates/bitwarden-core/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs index ff7a4dc62..6025ee765 100644 --- a/crates/bitwarden-core/src/auth/client_auth.rs +++ b/crates/bitwarden-core/src/auth/client_auth.rs @@ -32,7 +32,7 @@ pub struct ClientAuth<'a> { impl<'a> ClientAuth<'a> { pub async fn renew_token(&self) -> Result<()> { - renew_token(self.client).await + renew_token(&self.client.internal).await } #[cfg(feature = "secrets")] diff --git a/crates/bitwarden-core/src/auth/renew.rs b/crates/bitwarden-core/src/auth/renew.rs index 6a6f60a03..cd70fe7c4 100644 --- a/crates/bitwarden-core/src/auth/renew.rs +++ b/crates/bitwarden-core/src/auth/renew.rs @@ -4,22 +4,20 @@ use chrono::Utc; use crate::{auth::api::request::ApiTokenRequest, client::UserLoginMethod}; use crate::{ auth::api::{request::AccessTokenRequest, response::IdentityTokenResponse}, - client::{Client, LoginMethod, ServiceAccountLoginMethod}, + client::{internal::InternalClient, LoginMethod, ServiceAccountLoginMethod}, error::{Error, Result}, secrets_manager::state::{self, ClientState}, }; -pub(crate) async fn renew_token(client: &Client) -> Result<()> { +pub(crate) async fn renew_token(client: &InternalClient) -> Result<()> { const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60; let tokens = client - .internal .tokens .read() .expect("RwLock is not poisoned") .clone(); let login_method = client - .internal .login_method .read() .expect("RwLock is not poisoned") @@ -31,7 +29,6 @@ pub(crate) async fn renew_token(client: &Client) -> Result<()> { } let config = client - .internal .__api_configurations .read() .expect("RwLock is not poisoned") @@ -70,11 +67,9 @@ pub(crate) async fn renew_token(client: &Client) -> Result<()> { .send(&config) .await?; - if let (IdentityTokenResponse::Payload(r), Some(state_file), Ok(enc_settings)) = ( - &result, - state_file, - client.internal.get_encryption_settings(), - ) { + if let (IdentityTokenResponse::Payload(r), Some(state_file), Ok(enc_settings)) = + (&result, state_file, client.get_encryption_settings()) + { if let Some(enc_key) = enc_settings.get_key(&None) { let state = ClientState::new(r.access_token.clone(), enc_key.to_base64()); @@ -89,21 +84,15 @@ pub(crate) async fn renew_token(client: &Client) -> Result<()> { match res { IdentityTokenResponse::Refreshed(r) => { - client - .internal - .set_tokens(r.access_token, r.refresh_token, r.expires_in); + client.set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } IdentityTokenResponse::Authenticated(r) => { - client - .internal - .set_tokens(r.access_token, r.refresh_token, r.expires_in); + client.set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } IdentityTokenResponse::Payload(r) => { - client - .internal - .set_tokens(r.access_token, r.refresh_token, r.expires_in); + client.set_tokens(r.access_token, r.refresh_token, r.expires_in); return Ok(()); } _ => { diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index 51aa775fb..3ee9a6f8f 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -11,6 +11,7 @@ use super::{ #[cfg(feature = "internal")] use super::{flags::Flags, login_method::UserLoginMethod}; use crate::{ + auth::renew::renew_token, error::{Error, Result, VaultLocked}, DeviceType, }; @@ -148,7 +149,7 @@ impl InternalClient { pub 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(); + renew_token(self).await.ok(); self.__api_configurations .read() .expect("RwLock is not poisoned") From 606d6d6d61cac338b5b89c8a54c6d388dfe3a726 Mon Sep 17 00:00:00 2001 From: Hinton Date: Tue, 18 Jun 2024 10:26:08 +0200 Subject: [PATCH 18/28] Cleanup unnecessary code --- Cargo.lock | 7 -- crates/bitwarden-sm/Cargo.toml | 11 -- crates/bitwarden-vault/Cargo.toml | 1 + crates/bitwarden/Cargo.toml | 3 - crates/bitwarden/src/error.rs | 23 ---- .../src/tool/exporters/client_exporter.rs | 38 ------ crates/bitwarden/src/tool/exporters/mod.rs | 115 ------------------ crates/bitwarden/src/tool/mod.rs | 5 - crates/bitwarden/src/vault/client_vault.rs | 18 --- 9 files changed, 1 insertion(+), 220 deletions(-) delete mode 100644 crates/bitwarden/src/tool/exporters/client_exporter.rs delete mode 100644 crates/bitwarden/src/tool/exporters/mod.rs delete mode 100644 crates/bitwarden/src/tool/mod.rs delete mode 100644 crates/bitwarden/src/vault/client_vault.rs diff --git a/Cargo.lock b/Cargo.lock index 4d91eb6d5..a33af238f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,9 +367,7 @@ dependencies = [ "bitwarden-send", "bitwarden-sm", "bitwarden-vault", - "reqwest", "thiserror", - "uniffi", ] [[package]] @@ -604,17 +602,12 @@ dependencies = [ "bitwarden-core", "bitwarden-crypto", "chrono", - "rand", - "rand_chacha", - "reqwest", "schemars", "serde", "serde_json", "thiserror", - "tokio", "uniffi", "uuid", - "wiremock", ] [[package]] diff --git a/crates/bitwarden-sm/Cargo.toml b/crates/bitwarden-sm/Cargo.toml index 9af74d9aa..6580dcf0f 100644 --- a/crates/bitwarden-sm/Cargo.toml +++ b/crates/bitwarden-sm/Cargo.toml @@ -20,12 +20,6 @@ bitwarden-crypto = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", "serde", - "std", -], default-features = false } -rand = ">=0.8.5, <0.9" -reqwest = { version = ">=0.12, <0.13", features = [ - "http2", - "json", ], default-features = false } schemars = { version = ">=0.8.9, <0.9", features = ["uuid1", "chrono"] } serde = { version = ">=1.0, <2.0", features = ["derive"] } @@ -34,10 +28,5 @@ thiserror = ">=1.0.40, <2.0" uniffi = { version = "=0.27.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } -[dev-dependencies] -rand_chacha = "0.3.1" -tokio = { version = "1.36.0", features = ["rt", "macros"] } -wiremock = "0.6.0" - [lints] workspace = true diff --git a/crates/bitwarden-vault/Cargo.toml b/crates/bitwarden-vault/Cargo.toml index 22ae8bd6b..71d1696bd 100644 --- a/crates/bitwarden-vault/Cargo.toml +++ b/crates/bitwarden-vault/Cargo.toml @@ -43,6 +43,7 @@ uniffi = { version = "=0.27.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } [dev-dependencies] +bitwarden-core = { workspace = true, features = ["internal"] } tokio = { version = "1.36.0", features = ["rt", "macros"] } [lints] diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 214d7c0f0..a594ffa5a 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -34,7 +34,6 @@ uniffi = [ "bitwarden-generators/uniffi", "bitwarden-send/uniffi", "bitwarden-vault/uniffi", - "dep:uniffi", ] # Uniffi bindings secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API @@ -50,8 +49,6 @@ bitwarden-send = { workspace = true, optional = true } bitwarden-sm = { workspace = true, optional = true } bitwarden-vault = { workspace = true, optional = true } thiserror = ">=1.0.40, <2.0" -reqwest = { version = ">=0.12, <0.13", default-features = false } -uniffi = { version = "=0.27.2", optional = true, features = ["tokio"] } [lints] workspace = true diff --git a/crates/bitwarden/src/error.rs b/crates/bitwarden/src/error.rs index ba5edd798..9ff48060f 100644 --- a/crates/bitwarden/src/error.rs +++ b/crates/bitwarden/src/error.rs @@ -13,14 +13,6 @@ pub enum Error { #[error(transparent)] Core(#[from] bitwarden_core::Error), - #[error(transparent)] - MissingFieldError(#[from] bitwarden_core::MissingFieldError), - #[error(transparent)] - VaultLocked(#[from] bitwarden_core::VaultLocked), - - #[error("Cryptography error, {0}")] - Crypto(#[from] bitwarden_crypto::CryptoError), - // Generators #[cfg(feature = "internal")] #[error(transparent)] @@ -32,20 +24,12 @@ pub enum Error { #[error(transparent)] PasswordError(#[from] PasswordError), - // Send - #[cfg(feature = "internal")] - #[error(transparent)] - SendParseError(#[from] bitwarden_send::SendParseError), - // Vault #[cfg(feature = "internal")] #[error(transparent)] Cipher(#[from] bitwarden_vault::CipherError), #[cfg(feature = "internal")] #[error(transparent)] - VaultParse(#[from] bitwarden_vault::VaultParseError), - #[cfg(feature = "internal")] - #[error(transparent)] Totp(#[from] bitwarden_vault::TotpError), #[cfg(feature = "internal")] @@ -65,13 +49,6 @@ pub enum Error { #[cfg(all(feature = "uniffi", feature = "internal"))] #[error(transparent)] Fido2Client(#[from] bitwarden_fido::Fido2ClientError), - #[cfg(all(feature = "uniffi", feature = "internal"))] - #[error("Fido2 Callback error: {0:?}")] - Fido2CallbackError(#[from] bitwarden_fido::Fido2CallbackError), - - #[cfg(feature = "uniffi")] - #[error("Uniffi callback error: {0}")] - UniffiCallbackError(#[from] uniffi::UnexpectedUniFFICallbackError), #[error("Internal error: {0}")] Internal(Cow<'static, str>), diff --git a/crates/bitwarden/src/tool/exporters/client_exporter.rs b/crates/bitwarden/src/tool/exporters/client_exporter.rs deleted file mode 100644 index 5257538cd..000000000 --- a/crates/bitwarden/src/tool/exporters/client_exporter.rs +++ /dev/null @@ -1,38 +0,0 @@ -use bitwarden_vault::{Cipher, Collection, Folder}; - -use crate::{ - error::Result, - tool::exporters::{export_organization_vault, export_vault, ExportFormat}, - Client, -}; - -pub struct ClientExporters<'a> { - pub(crate) client: &'a crate::Client, -} - -impl<'a> ClientExporters<'a> { - /// **Draft:** Export the vault as a CSV, JSON, or encrypted JSON file. - pub fn export_vault( - &self, - folders: Vec, - ciphers: Vec, - format: ExportFormat, - ) -> Result { - export_vault(self.client, folders, ciphers, format) - } - - pub fn export_organization_vault( - &self, - collections: Vec, - ciphers: Vec, - format: ExportFormat, - ) -> Result { - export_organization_vault(collections, ciphers, format) - } -} - -impl<'a> Client { - pub fn exporters(&'a self) -> ClientExporters<'a> { - ClientExporters { client: self } - } -} diff --git a/crates/bitwarden/src/tool/exporters/mod.rs b/crates/bitwarden/src/tool/exporters/mod.rs deleted file mode 100644 index 0c87bc558..000000000 --- a/crates/bitwarden/src/tool/exporters/mod.rs +++ /dev/null @@ -1,115 +0,0 @@ -use bitwarden_core::VaultLocked; -use bitwarden_crypto::KeyDecryptable; -use bitwarden_exporters::export; -use bitwarden_vault::{Cipher, CipherView, Collection, Folder, FolderView}; -use schemars::JsonSchema; - -use crate::{ - client::{LoginMethod, UserLoginMethod}, - error::{Error, Result}, - Client, -}; - -mod client_exporter; -pub use client_exporter::ClientExporters; - -#[derive(JsonSchema)] -#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] -pub enum ExportFormat { - Csv, - Json, - EncryptedJson { password: String }, -} - -pub(super) fn export_vault( - client: &Client, - folders: Vec, - ciphers: Vec, - format: ExportFormat, -) -> Result { - let enc = client.get_encryption_settings()?; - let key = enc.get_key(&None).ok_or(VaultLocked)?; - - let folders: Vec = folders.decrypt_with_key(key)?; - let folders: Vec = - folders.into_iter().flat_map(|f| f.try_into()).collect(); - - let ciphers: Vec = ciphers.decrypt_with_key(key)?; - let ciphers: Vec = - ciphers.into_iter().flat_map(|c| c.try_into()).collect(); - - let format = convert_format(client, format)?; - - Ok(export(folders, ciphers, format)?) -} - -fn convert_format( - client: &Client, - format: ExportFormat, -) -> Result { - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; - - let kdf = match login_method.as_ref() { - LoginMethod::User( - UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, - ) => kdf, - _ => return Err(Error::NotAuthenticated), - }; - - Ok(match format { - ExportFormat::Csv => bitwarden_exporters::Format::Csv, - ExportFormat::Json => bitwarden_exporters::Format::Json, - ExportFormat::EncryptedJson { password } => bitwarden_exporters::Format::EncryptedJson { - password, - kdf: kdf.clone(), - }, - }) -} - -pub(super) fn export_organization_vault( - _collections: Vec, - _ciphers: Vec, - _format: ExportFormat, -) -> Result { - todo!(); -} - -#[cfg(test)] -mod tests { - use std::num::NonZeroU32; - - use bitwarden_crypto::Kdf; - - use super::*; - - #[test] - fn test_convert_format() { - 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(), - kdf: Kdf::PBKDF2 { - iterations: NonZeroU32::new(600_000).unwrap(), - }, - })); - - assert!(matches!( - convert_format(&client, ExportFormat::Csv).unwrap(), - bitwarden_exporters::Format::Csv - )); - assert!(matches!( - convert_format(&client, ExportFormat::Json).unwrap(), - bitwarden_exporters::Format::Json - )); - assert!(matches!( - convert_format( - &client, - ExportFormat::EncryptedJson { - password: "password".to_string() - } - ) - .unwrap(), - bitwarden_exporters::Format::EncryptedJson { .. } - )); - } -} diff --git a/crates/bitwarden/src/tool/mod.rs b/crates/bitwarden/src/tool/mod.rs deleted file mode 100644 index f67ef0fc1..000000000 --- a/crates/bitwarden/src/tool/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod exporters; -pub use exporters::{ClientExporters, ExportFormat}; -mod client_generator; -pub use bitwarden_send::*; -pub use client_generator::ClientGenerator; diff --git a/crates/bitwarden/src/vault/client_vault.rs b/crates/bitwarden/src/vault/client_vault.rs deleted file mode 100644 index 49ba5edd7..000000000 --- a/crates/bitwarden/src/vault/client_vault.rs +++ /dev/null @@ -1,18 +0,0 @@ -use super::sync::{sync, SyncRequest, SyncResponse}; -use crate::{error::Result, Client}; - -pub struct ClientVault<'a> { - pub(crate) client: &'a crate::Client, -} - -impl<'a> ClientVault<'a> { - pub async fn sync(&self, input: &SyncRequest) -> Result { - sync(self.client, input).await - } -} - -impl<'a> Client { - pub fn vault(&'a self) -> ClientVault<'a> { - ClientVault { client: self } - } -} From 4650642ab2ae2f0784723f5a833d48ae1f06776e Mon Sep 17 00:00:00 2001 From: Hinton Date: Tue, 18 Jun 2024 15:34:36 +0200 Subject: [PATCH 19/28] Remove unecessary bitwarden-core/internal for secrets --- crates/bitwarden/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index a594ffa5a..87fb977b9 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -35,7 +35,7 @@ uniffi = [ "bitwarden-send/uniffi", "bitwarden-vault/uniffi", ] # Uniffi bindings -secrets = ["bitwarden-core/internal", "dep:bitwarden-sm"] # Secrets manager API +secrets = ["dep:bitwarden-sm"] # Secrets manager API [dependencies] bitwarden-api-api = { workspace = true } From 69d45ddc340fa74e2553ff25858d8041684faa62 Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 20 Jun 2024 16:50:12 +0200 Subject: [PATCH 20/28] Fix platform-verifier rustls missmatch due to conflict --- Cargo.lock | 30 ++++++++---------------------- crates/bitwarden-core/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dec3700b..cd2087415 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2004,7 +2004,7 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.23.10", + "rustls", "rustls-pki-types", "tokio", "tokio-rustls", @@ -3005,7 +3005,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.10", + "rustls", "thiserror", "tokio", "tracing", @@ -3021,7 +3021,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.10", + "rustls", "slab", "thiserror", "tinyvec", @@ -3175,7 +3175,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.10", + "rustls", "rustls-pemfile", "rustls-pki-types", "serde", @@ -3278,20 +3278,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - [[package]] name = "rustls" version = "0.23.10" @@ -3337,16 +3323,16 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-platform-verifier" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c35b9a497e588f1fb2e1d18a0d46a6d057710f34c3da7084b27353b319453cc" +checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" dependencies = [ "core-foundation", "core-foundation-sys", "jni", "log", "once_cell", - "rustls 0.22.4", + "rustls", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", @@ -4069,7 +4055,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.10", + "rustls", "rustls-pki-types", "tokio", ] diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index a54256805..dcd525e74 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -74,7 +74,7 @@ zxcvbn = ">= 2.2.2, <3.0" reqwest = { version = ">=0.12.5, <0.13", features = [ "rustls-tls-manual-roots", ], default-features = false } -rustls-platform-verifier = "0.2.0" +rustls-platform-verifier = "0.3.1" [target.'cfg(target_os = "android")'.dependencies] # On android, the use of rustls-platform-verifier is more complicated and going through some changes at the moment, so we fall back to using webpki-roots From 148110d0836185ff24e25b2dc7eb0d241e7e8ee5 Mon Sep 17 00:00:00 2001 From: Hinton Date: Thu, 20 Jun 2024 16:53:52 +0200 Subject: [PATCH 21/28] Undo changes to core/uniffi --- crates/bitwarden-core/uniffi.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bitwarden-core/uniffi.toml b/crates/bitwarden-core/uniffi.toml index c5fdba5c2..7a804ef1d 100644 --- a/crates/bitwarden-core/uniffi.toml +++ b/crates/bitwarden-core/uniffi.toml @@ -1,9 +1,9 @@ [bindings.kotlin] -package_name = "com.bitwarden.bitwarden" +package_name = "com.bitwarden.core" generate_immutable_records = true android = true [bindings.swift] -ffi_module_name = "BitwardenBitwardenFFI" -module_name = "BitwardenBitwarden" +ffi_module_name = "BitwardenCoreFFI" +module_name = "BitwardenCore" generate_immutable_records = true From 0b934ee43c18673f9921f762a47698d4a1019fd2 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 16:06:13 +0200 Subject: [PATCH 22/28] Fix compile errors --- .../api/request/auth_request_token_request.rs | 1 + .../src/auth/api/request/mod.rs | 17 +++++----- crates/bitwarden-core/src/auth/client_auth.rs | 32 ++++++++----------- crates/bitwarden-core/src/auth/login/mod.rs | 6 +++- .../bitwarden-core/src/auth/login/password.rs | 4 ++- crates/bitwarden-core/src/auth/mod.rs | 18 +++++++---- .../src/auth/password/validate.rs | 14 ++++++-- crates/bitwarden-core/src/auth/register.rs | 4 +-- crates/bitwarden-core/src/auth/renew.rs | 15 +++++---- crates/bitwarden-core/src/client/client.rs | 2 -- .../src/client/encryption_settings.rs | 1 + crates/bitwarden-core/src/client/internal.rs | 19 +++++++---- .../bitwarden-core/src/client/login_method.rs | 9 ++++-- crates/bitwarden-core/src/client/mod.rs | 8 ++--- .../bitwarden-core/src/mobile/client_kdf.rs | 4 +-- crates/bitwarden-core/src/mobile/crypto.rs | 11 ++++--- .../src/platform/generate_fingerprint.rs | 4 ++- crates/bitwarden-fido/Cargo.toml | 2 +- crates/bitwarden-generators/Cargo.toml | 2 +- crates/bitwarden-vault/Cargo.toml | 2 +- crates/bitwarden-vault/src/cipher/cipher.rs | 1 - crates/bitwarden/src/lib.rs | 1 + 22 files changed, 103 insertions(+), 74 deletions(-) diff --git a/crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs b/crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs index 17ef52c26..2b2a47839 100644 --- a/crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs +++ b/crates/bitwarden-core/src/auth/api/request/auth_request_token_request.rs @@ -26,6 +26,7 @@ pub struct AuthRequestTokenRequest { access_code: String, } +#[allow(dead_code)] impl AuthRequestTokenRequest { pub fn new( email: &str, diff --git a/crates/bitwarden-core/src/auth/api/request/mod.rs b/crates/bitwarden-core/src/auth/api/request/mod.rs index c0cb45251..0d9f39877 100644 --- a/crates/bitwarden-core/src/auth/api/request/mod.rs +++ b/crates/bitwarden-core/src/auth/api/request/mod.rs @@ -1,21 +1,20 @@ +#[cfg(feature = "secrets")] mod access_token_request; -#[cfg(feature = "internal")] +#[cfg(feature = "secrets")] +pub(crate) use access_token_request::*; + mod api_token_request; +pub(crate) use api_token_request::*; + #[cfg(feature = "internal")] mod password_token_request; #[cfg(feature = "internal")] -mod renew_token_request; +pub(crate) use password_token_request::*; -pub(crate) use access_token_request::*; -#[cfg(feature = "internal")] -pub(crate) use api_token_request::*; +mod renew_token_request; use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine}; -#[cfg(feature = "internal")] -pub(crate) use password_token_request::*; -#[cfg(feature = "internal")] pub(crate) use renew_token_request::*; -#[cfg(feature = "internal")] mod auth_request_token_request; #[cfg(feature = "internal")] pub(crate) use auth_request_token_request::*; diff --git a/crates/bitwarden-core/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs index 6025ee765..fa48481e6 100644 --- a/crates/bitwarden-core/src/auth/client_auth.rs +++ b/crates/bitwarden-core/src/auth/client_auth.rs @@ -1,30 +1,26 @@ #[cfg(feature = "internal")] -use bitwarden_crypto::{AsymmetricEncString, DeviceKey, TrustDeviceResponse}; +use bitwarden_crypto::{AsymmetricEncString, DeviceKey, Kdf, TrustDeviceResponse}; #[cfg(feature = "internal")] use crate::auth::login::NewAuthRequestResponse; #[cfg(feature = "secrets")] use crate::auth::login::{login_access_token, AccessTokenLoginRequest, AccessTokenLoginResponse}; -use crate::{auth::renew::renew_token, error::Result, Client}; #[cfg(feature = "internal")] -use crate::{ - auth::{ - auth_request::{approve_auth_request, new_auth_request}, - login::{ - login_api_key, login_password, send_two_factor_email, ApiKeyLoginRequest, - ApiKeyLoginResponse, PasswordLoginRequest, PasswordLoginResponse, - TwoFactorEmailRequest, - }, - password::{ - password_strength, satisfies_policy, validate_password, validate_password_user_key, - MasterPasswordPolicyOptions, - }, - register::{make_register_keys, register}, - tde::{make_register_tde_keys, RegisterTdeKeyResponse}, - AuthRequestResponse, RegisterKeyResponse, RegisterRequest, +use crate::auth::{ + auth_request::{approve_auth_request, new_auth_request}, + login::{ + login_api_key, login_password, send_two_factor_email, ApiKeyLoginRequest, + ApiKeyLoginResponse, PasswordLoginRequest, PasswordLoginResponse, TwoFactorEmailRequest, + }, + password::{ + password_strength, satisfies_policy, validate_password, validate_password_user_key, + MasterPasswordPolicyOptions, }, - client::Kdf, + register::{make_register_keys, register}, + tde::{make_register_tde_keys, RegisterTdeKeyResponse}, + AuthRequestResponse, RegisterKeyResponse, RegisterRequest, }; +use crate::{auth::renew::renew_token, error::Result, Client}; pub struct ClientAuth<'a> { pub(crate) client: &'a crate::Client, diff --git a/crates/bitwarden-core/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs index 04c2804b6..0c90dc973 100644 --- a/crates/bitwarden-core/src/auth/login/mod.rs +++ b/crates/bitwarden-core/src/auth/login/mod.rs @@ -1,6 +1,8 @@ #[cfg(feature = "internal")] +use bitwarden_crypto::Kdf; +#[cfg(feature = "internal")] use { - crate::{client::Kdf, error::Result, Client}, + crate::{error::Result, Client}, bitwarden_api_identity::{ apis::accounts_api::accounts_prelogin_post, models::{PreloginRequestModel, PreloginResponseModel}, @@ -9,11 +11,13 @@ use { pub mod response; +#[cfg(any(feature = "internal", feature = "secrets"))] mod password; #[cfg(feature = "internal")] pub(crate) use password::login_password; #[cfg(feature = "internal")] pub use password::PasswordLoginRequest; +#[cfg(any(feature = "internal", feature = "secrets"))] pub use password::PasswordLoginResponse; #[cfg(feature = "internal")] mod two_factor; diff --git a/crates/bitwarden-core/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs index c5d32bdaf..4536657d3 100644 --- a/crates/bitwarden-core/src/auth/login/password.rs +++ b/crates/bitwarden-core/src/auth/login/password.rs @@ -1,4 +1,6 @@ #[cfg(feature = "internal")] +use bitwarden_crypto::Kdf; +#[cfg(feature = "internal")] use log::info; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -6,7 +8,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "internal")] use crate::{ auth::{api::request::PasswordTokenRequest, login::TwoFactorRequest}, - client::{Kdf, LoginMethod}, + client::LoginMethod, Client, }; use crate::{ diff --git a/crates/bitwarden-core/src/auth/mod.rs b/crates/bitwarden-core/src/auth/mod.rs index 525645c38..b092ba98a 100644 --- a/crates/bitwarden-core/src/auth/mod.rs +++ b/crates/bitwarden-core/src/auth/mod.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "internal")] +use bitwarden_crypto::{HashPurpose, Kdf, MasterKey}; + mod access_token; pub(super) mod api; pub mod client_auth; @@ -8,25 +11,26 @@ pub mod password; pub mod renew; pub use access_token::AccessToken; pub use jwt_token::JWTToken; + #[cfg(feature = "internal")] -mod register; +mod auth_request; +#[cfg(feature = "internal")] +pub use auth_request::AuthRequestResponse; #[cfg(feature = "internal")] pub(crate) use auth_request::{auth_request_decrypt_master_key, auth_request_decrypt_user_key}; + #[cfg(feature = "internal")] -use bitwarden_crypto::{HashPurpose, MasterKey}; +mod register; #[cfg(feature = "internal")] pub use register::{RegisterKeyResponse, RegisterRequest}; -#[cfg(feature = "internal")] -mod auth_request; -#[cfg(feature = "internal")] -pub use auth_request::AuthRequestResponse; + #[cfg(feature = "internal")] mod tde; #[cfg(feature = "internal")] pub use tde::RegisterTdeKeyResponse; #[cfg(feature = "internal")] -use crate::{client::Kdf, error::Result}; +use crate::error::Result; #[cfg(feature = "internal")] fn determine_password_hash( diff --git a/crates/bitwarden-core/src/auth/password/validate.rs b/crates/bitwarden-core/src/auth/password/validate.rs index 8aaa4eda2..ebb5395d1 100644 --- a/crates/bitwarden-core/src/auth/password/validate.rs +++ b/crates/bitwarden-core/src/auth/password/validate.rs @@ -18,6 +18,7 @@ pub(crate) fn validate_password( .get_login_method() .ok_or(Error::NotAuthenticated)?; + #[allow(irrefutable_let_patterns)] if let LoginMethod::User(login_method) = login_method.as_ref() { match login_method { UserLoginMethod::Username { email, kdf, .. } @@ -50,6 +51,7 @@ pub(crate) fn validate_password_user_key( .get_login_method() .ok_or(Error::NotAuthenticated)?; + #[allow(irrefutable_let_patterns)] if let LoginMethod::User(login_method) = login_method.as_ref() { match login_method { UserLoginMethod::Username { email, kdf, .. } @@ -81,13 +83,15 @@ pub(crate) fn validate_password_user_key( #[cfg(test)] mod tests { + use bitwarden_crypto::Kdf; + use crate::auth::password::{validate::validate_password_user_key, validate_password}; #[test] fn test_validate_password() { use std::num::NonZeroU32; - use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; + use crate::client::{Client, LoginMethod, UserLoginMethod}; let client = Client::new(None); client @@ -113,7 +117,9 @@ mod tests { fn test_validate_password_user_key() { use std::num::NonZeroU32; - use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; + use bitwarden_crypto::Kdf; + + use crate::client::{Client, LoginMethod, UserLoginMethod}; let client = Client::new(None); @@ -156,7 +162,9 @@ mod tests { fn test_validate_password_user_key_wrong_password() { use std::num::NonZeroU32; - use crate::client::{Client, Kdf, LoginMethod, UserLoginMethod}; + use bitwarden_crypto::Kdf; + + use crate::client::{Client, LoginMethod, UserLoginMethod}; let client = Client::new(None); diff --git a/crates/bitwarden-core/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs index cf0c36144..07e5e87ba 100644 --- a/crates/bitwarden-core/src/auth/register.rs +++ b/crates/bitwarden-core/src/auth/register.rs @@ -2,11 +2,11 @@ use bitwarden_api_identity::{ apis::accounts_api::accounts_register_post, models::{KeysRequestModel, RegisterRequestModel}, }; -use bitwarden_crypto::{default_pbkdf2_iterations, HashPurpose, MasterKey, RsaKeyPair}; +use bitwarden_crypto::{default_pbkdf2_iterations, HashPurpose, Kdf, MasterKey, RsaKeyPair}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use crate::{client::Kdf, error::Result, Client}; +use crate::{error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] diff --git a/crates/bitwarden-core/src/auth/renew.rs b/crates/bitwarden-core/src/auth/renew.rs index cd70fe7c4..d53534d58 100644 --- a/crates/bitwarden-core/src/auth/renew.rs +++ b/crates/bitwarden-core/src/auth/renew.rs @@ -1,13 +1,16 @@ use chrono::Utc; -#[cfg(feature = "internal")] -use crate::{auth::api::request::ApiTokenRequest, client::UserLoginMethod}; +#[cfg(feature = "secrets")] use crate::{ - auth::api::{request::AccessTokenRequest, response::IdentityTokenResponse}, - client::{internal::InternalClient, LoginMethod, ServiceAccountLoginMethod}, - error::{Error, Result}, + auth::api::request::AccessTokenRequest, + client::ServiceAccountLoginMethod, secrets_manager::state::{self, ClientState}, }; +use crate::{ + auth::api::{request::ApiTokenRequest, response::IdentityTokenResponse}, + client::{internal::InternalClient, LoginMethod, UserLoginMethod}, + error::{Error, Result}, +}; pub(crate) async fn renew_token(client: &InternalClient) -> Result<()> { const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60; @@ -35,7 +38,6 @@ pub(crate) async fn renew_token(client: &InternalClient) -> Result<()> { .clone(); let res = match login_method.as_ref() { - #[cfg(feature = "internal")] LoginMethod::User(u) => match u { UserLoginMethod::Username { client_id, .. } => { let refresh = tokens.refresh_token.ok_or(Error::NotAuthenticated)?; @@ -54,6 +56,7 @@ pub(crate) async fn renew_token(client: &InternalClient) -> Result<()> { .await? } }, + #[cfg(feature = "secrets")] LoginMethod::ServiceAccount(s) => match s { ServiceAccountLoginMethod::AccessToken { access_token, diff --git a/crates/bitwarden-core/src/client/client.rs b/crates/bitwarden-core/src/client/client.rs index 465e3a1db..3ea4ae7e8 100644 --- a/crates/bitwarden-core/src/client/client.rs +++ b/crates/bitwarden-core/src/client/client.rs @@ -1,7 +1,5 @@ use std::sync::{Arc, RwLock}; -#[cfg(feature = "internal")] -pub use bitwarden_crypto::Kdf; use reqwest::header::{self, HeaderValue}; use super::internal::InternalClient; diff --git a/crates/bitwarden-core/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs index 6b781d750..138d1568e 100644 --- a/crates/bitwarden-core/src/client/encryption_settings.rs +++ b/crates/bitwarden-core/src/client/encryption_settings.rs @@ -59,6 +59,7 @@ impl EncryptionSettings { /// Initialize the encryption settings with only a single decrypted key. /// This is used only for logging in Secrets Manager with an access token + #[cfg(feature = "secrets")] pub(crate) fn new_single_key(key: SymmetricCryptoKey) -> Self { EncryptionSettings { user_key: key, diff --git a/crates/bitwarden-core/src/client/internal.rs b/crates/bitwarden-core/src/client/internal.rs index 3ee9a6f8f..55122b9a1 100644 --- a/crates/bitwarden-core/src/client/internal.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -1,18 +1,22 @@ use std::sync::{Arc, RwLock}; -use bitwarden_crypto::{AsymmetricEncString, EncString, Kdf, MasterKey, SymmetricCryptoKey}; +#[cfg(any(feature = "internal", feature = "secrets"))] +use bitwarden_crypto::SymmetricCryptoKey; +#[cfg(feature = "internal")] +use bitwarden_crypto::{AsymmetricEncString, EncString, Kdf, MasterKey}; use chrono::Utc; use uuid::Uuid; -use super::{ - encryption_settings::EncryptionSettings, - login_method::{LoginMethod, ServiceAccountLoginMethod}, -}; +#[cfg(feature = "secrets")] +use super::login_method::ServiceAccountLoginMethod; +use super::{encryption_settings::EncryptionSettings, login_method::LoginMethod}; #[cfg(feature = "internal")] use super::{flags::Flags, login_method::UserLoginMethod}; +#[cfg(feature = "internal")] +use crate::error::Error; use crate::{ auth::renew::renew_token, - error::{Error, Result, VaultLocked}, + error::{Result, VaultLocked}, DeviceType, }; @@ -81,6 +85,7 @@ impl InternalClient { .expect("RwLock is not poisoned") .as_deref() { + #[cfg(feature = "secrets")] Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { organization_id, .. @@ -89,6 +94,7 @@ impl InternalClient { } } + #[cfg(any(feature = "internal", feature = "secrets"))] pub(crate) fn set_login_method(&self, login_method: LoginMethod) { use log::debug; @@ -215,6 +221,7 @@ impl InternalClient { self.initialize_user_crypto_decrypted_key(decrypted_user_key, private_key) } + #[cfg(feature = "secrets")] pub(crate) fn initialize_crypto_single_key(&self, key: SymmetricCryptoKey) { *self .encryption_settings diff --git a/crates/bitwarden-core/src/client/login_method.rs b/crates/bitwarden-core/src/client/login_method.rs index e39ad7818..67db15a71 100644 --- a/crates/bitwarden-core/src/client/login_method.rs +++ b/crates/bitwarden-core/src/client/login_method.rs @@ -1,21 +1,25 @@ +#[cfg(feature = "secrets")] use std::path::PathBuf; use bitwarden_crypto::Kdf; +#[cfg(feature = "secrets")] use uuid::Uuid; +#[cfg(feature = "secrets")] use crate::auth::AccessToken; #[derive(Debug)] pub(crate) enum LoginMethod { - #[cfg(feature = "internal")] + #[allow(dead_code)] User(UserLoginMethod), // TODO: Organizations supports api key // Organization(OrganizationLoginMethod), + #[cfg(feature = "secrets")] ServiceAccount(ServiceAccountLoginMethod), } +#[allow(dead_code)] #[derive(Debug)] -#[cfg(feature = "internal")] pub(crate) enum UserLoginMethod { Username { client_id: String, @@ -31,6 +35,7 @@ pub(crate) enum UserLoginMethod { }, } +#[cfg(feature = "secrets")] #[derive(Debug)] pub(crate) enum ServiceAccountLoginMethod { AccessToken { diff --git a/crates/bitwarden-core/src/client/mod.rs b/crates/bitwarden-core/src/client/mod.rs index 4c352d652..1ef7d9357 100644 --- a/crates/bitwarden-core/src/client/mod.rs +++ b/crates/bitwarden-core/src/client/mod.rs @@ -1,6 +1,5 @@ //! Bitwarden SDK Client -pub(crate) use client::*; #[allow(clippy::module_inception)] mod client; pub mod client_settings; @@ -8,10 +7,9 @@ pub mod encryption_settings; pub mod internal; pub use internal::ApiConfigurations; pub mod login_method; -#[cfg(feature = "internal")] -pub(crate) use login_method::UserLoginMethod; -pub(crate) use login_method::{LoginMethod, ServiceAccountLoginMethod}; - +#[cfg(feature = "secrets")] +pub(crate) use login_method::ServiceAccountLoginMethod; +pub(crate) use login_method::{LoginMethod, UserLoginMethod}; #[cfg(feature = "internal")] mod flags; diff --git a/crates/bitwarden-core/src/mobile/client_kdf.rs b/crates/bitwarden-core/src/mobile/client_kdf.rs index 4e62e5d59..5ec7aec77 100644 --- a/crates/bitwarden-core/src/mobile/client_kdf.rs +++ b/crates/bitwarden-core/src/mobile/client_kdf.rs @@ -1,6 +1,6 @@ -use bitwarden_crypto::HashPurpose; +use bitwarden_crypto::{HashPurpose, Kdf}; -use crate::{client::Kdf, error::Result, mobile::kdf::hash_password, Client}; +use crate::{error::Result, mobile::kdf::hash_password, Client}; pub struct ClientKdf<'a> { pub(crate) client: &'a crate::Client, diff --git a/crates/bitwarden-core/src/mobile/crypto.rs b/crates/bitwarden-core/src/mobile/crypto.rs index 518690d8e..2b6992496 100644 --- a/crates/bitwarden-core/src/mobile/crypto.rs +++ b/crates/bitwarden-core/src/mobile/crypto.rs @@ -2,14 +2,13 @@ use std::collections::HashMap; use bitwarden_crypto::{AsymmetricEncString, EncString}; #[cfg(feature = "internal")] -use bitwarden_crypto::{KeyDecryptable, KeyEncryptable, MasterKey, SymmetricCryptoKey}; +use bitwarden_crypto::{Kdf, KeyDecryptable, KeyEncryptable, MasterKey, SymmetricCryptoKey}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[cfg(feature = "internal")] use crate::client::{LoginMethod, UserLoginMethod}; use crate::{ - client::Kdf, error::{Error, Result}, Client, VaultLocked, }; @@ -218,7 +217,8 @@ pub fn update_password(client: &Client, new_password: String) -> Result MasterKey::derive(new_password.as_bytes(), email.as_bytes(), kdf)?, - _ => return Err(Error::NotAuthenticated), + #[cfg(feature = "secrets")] + LoginMethod::ServiceAccount(_) => return Err(Error::NotAuthenticated), }; let new_key = new_master_key.encrypt_user_key(user_key)?; @@ -288,7 +288,8 @@ fn derive_pin_protected_user_key( UserLoginMethod::Username { email, kdf, .. } | UserLoginMethod::ApiKey { email, kdf, .. }, ) => MasterKey::derive(pin.as_bytes(), email.as_bytes(), kdf)?, - _ => return Err(Error::NotAuthenticated), + #[cfg(feature = "secrets")] + LoginMethod::ServiceAccount(_) => return Err(Error::NotAuthenticated), }; Ok(derived_key.encrypt_user_key(user_key)?) @@ -315,7 +316,7 @@ pub(super) fn enroll_admin_password_reset( #[cfg(test)] mod tests { use super::*; - use crate::{client::Kdf, Client}; + use crate::Client; #[tokio::test] async fn test_update_password() { diff --git a/crates/bitwarden-core/src/platform/generate_fingerprint.rs b/crates/bitwarden-core/src/platform/generate_fingerprint.rs index 39cd17ceb..6ac41e149 100644 --- a/crates/bitwarden-core/src/platform/generate_fingerprint.rs +++ b/crates/bitwarden-core/src/platform/generate_fingerprint.rs @@ -54,8 +54,10 @@ pub(crate) fn generate_user_fingerprint( mod tests { use std::num::NonZeroU32; + use bitwarden_crypto::Kdf; + use super::*; - use crate::{client::Kdf, Client}; + use crate::Client; #[test] fn test_generate_user_fingerprint() { diff --git a/crates/bitwarden-fido/Cargo.toml b/crates/bitwarden-fido/Cargo.toml index 3e02f544c..de9ec79d5 100644 --- a/crates/bitwarden-fido/Cargo.toml +++ b/crates/bitwarden-fido/Cargo.toml @@ -14,7 +14,7 @@ license-file.workspace = true keywords.workspace = true [features] -uniffi = ["dep:uniffi"] +uniffi = ["dep:uniffi", "bitwarden-core/uniffi", "bitwarden-vault/uniffi"] [dependencies] async-trait = ">=0.1.80, <0.2" diff --git a/crates/bitwarden-generators/Cargo.toml b/crates/bitwarden-generators/Cargo.toml index a6317177b..629722548 100644 --- a/crates/bitwarden-generators/Cargo.toml +++ b/crates/bitwarden-generators/Cargo.toml @@ -17,7 +17,7 @@ keywords.workspace = true uniffi = ["dep:uniffi"] # Uniffi bindings [dependencies] -bitwarden-core = { workspace = true } +bitwarden-core = { workspace = true, features = ["internal"] } bitwarden-crypto = { workspace = true } rand = ">=0.8.5, <0.9" reqwest = { version = ">=0.12.5, <0.13", features = [ diff --git a/crates/bitwarden-vault/Cargo.toml b/crates/bitwarden-vault/Cargo.toml index 943efc07d..b022796b1 100644 --- a/crates/bitwarden-vault/Cargo.toml +++ b/crates/bitwarden-vault/Cargo.toml @@ -23,7 +23,7 @@ uniffi = [ [dependencies] base64 = ">=0.21.2, <0.23" bitwarden-api-api = { workspace = true } -bitwarden-core = { workspace = true } +bitwarden-core = { workspace = true, features = ["internal"] } bitwarden-crypto = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index 2ddf33201..a4aa639ea 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -16,7 +16,6 @@ use super::{ local_data::{LocalData, LocalDataView}, secure_note, }; -#[cfg(feature = "uniffi")] use crate::Fido2CredentialView; use crate::{password_history, Fido2CredentialFullView, Login, LoginView, VaultParseError}; diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index 1423976ff..d1ab75089 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -79,6 +79,7 @@ pub mod internal { pub use bitwarden_vault::*; } + #[cfg(feature = "uniffi")] pub mod fido { pub use bitwarden_fido::*; } From 3121b97d80888a1b21b4955c53cbd143df0b00f4 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 16:15:58 +0200 Subject: [PATCH 23/28] fmt --- crates/bitwarden-vault/src/cipher/cipher.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index a4aa639ea..c1e84638c 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -16,8 +16,10 @@ use super::{ local_data::{LocalData, LocalDataView}, secure_note, }; -use crate::Fido2CredentialView; -use crate::{password_history, Fido2CredentialFullView, Login, LoginView, VaultParseError}; +use crate::{ + password_history, Fido2CredentialFullView, Fido2CredentialView, Login, LoginView, + VaultParseError, +}; #[derive(Debug, Error)] pub enum CipherError { From 5bb63ef05fe7e8ed56c854578a732962f76cc1c4 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 16:40:27 +0200 Subject: [PATCH 24/28] Fix readme --- crates/bitwarden/README.md | 6 ++++-- crates/bitwarden/src/lib.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/crates/bitwarden/README.md b/crates/bitwarden/README.md index ed0139a65..b0364a19e 100644 --- a/crates/bitwarden/README.md +++ b/crates/bitwarden/README.md @@ -19,8 +19,10 @@ Rust **1.71** or higher. ```rust use bitwarden::{ - auth::login::AccessTokenLoginRequest, error::Result, - secrets_manager::secrets::SecretIdentifiersRequest, Client, ClientSettings, DeviceType, + auth::login::AccessTokenLoginRequest, + error::Result, + secrets_manager::{secrets::SecretIdentifiersRequest, ClientSecretsExt}, + Client, ClientSettings, DeviceType, }; use uuid::Uuid; diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index d1ab75089..40168761c 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -15,13 +15,13 @@ //! All operations in this crate are done via a [Client]: //! //! ```rust -//! use bitwarden::{ -//! auth::login::AccessTokenLoginRequest, -//! error::Result, -//! secrets_manager::{secrets::SecretIdentifiersRequest, ClientSecretsExt}, -//! Client, ClientSettings, DeviceType, -//! }; -//! use uuid::Uuid; +//! use bitwarden::{ +//! auth::login::AccessTokenLoginRequest, +//! error::Result, +//! secrets_manager::{secrets::SecretIdentifiersRequest, ClientSecretsExt}, +//! Client, ClientSettings, DeviceType, +//! }; +//! use uuid::Uuid; //! //! async fn test() -> Result<()> { //! // Use the default values From bc59e323817e8f050b281ca43c59940e2ce901bb Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 16:56:52 +0200 Subject: [PATCH 25/28] Remove wasm-bindgen feature --- Cargo.lock | 1 + crates/bitwarden-core/Cargo.toml | 1 - crates/bitwarden-wasm/Cargo.toml | 8 ++++++++ crates/bitwarden-wasm/build.sh | 4 ++-- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79d2733f7..55266a08b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -665,6 +665,7 @@ version = "0.1.0" dependencies = [ "argon2", "bitwarden-json", + "chrono", "console_error_panic_hook", "console_log", "js-sys", diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index dcd525e74..a34ca1fa8 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -28,7 +28,6 @@ uniffi = [ "dep:p256", ] # Uniffi bindings secrets = [] # Secrets manager API -wasm-bindgen = ["chrono/wasmbind"] [dependencies] async-trait = ">=0.1.80, <0.2" diff --git a/crates/bitwarden-wasm/Cargo.toml b/crates/bitwarden-wasm/Cargo.toml index a4ba8b6ae..c4be614d3 100644 --- a/crates/bitwarden-wasm/Cargo.toml +++ b/crates/bitwarden-wasm/Cargo.toml @@ -34,5 +34,13 @@ wasm-bindgen-futures = "0.4.41" [dev-dependencies] wasm-bindgen-test = "0.3.41" +[target.'cfg(target_arch = "wasm32")'.dependencies] +chrono = { version = ">=0.4.26, <0.5", features = [ + "clock", + "serde", + "std", + "wasmbind", +], default-features = false } + [lints] workspace = true diff --git a/crates/bitwarden-wasm/build.sh b/crates/bitwarden-wasm/build.sh index ae32c775d..d49b12de3 100755 --- a/crates/bitwarden-wasm/build.sh +++ b/crates/bitwarden-wasm/build.sh @@ -4,12 +4,12 @@ cd ../../ if [ "$1" != "-r" ]; then # Dev - cargo build -p bitwarden -p bitwarden-wasm --target wasm32-unknown-unknown --features wasm-bindgen + cargo build -p bitwarden-wasm --target wasm32-unknown-unknown wasm-bindgen --target bundler --out-dir languages/js/wasm ./target/wasm32-unknown-unknown/debug/bitwarden_wasm.wasm wasm-bindgen --target nodejs --out-dir languages/js/wasm/node ./target/wasm32-unknown-unknown/debug/bitwarden_wasm.wasm else # Release - cargo build -p bitwarden -p bitwarden-wasm --target wasm32-unknown-unknown --features wasm-bindgen --release + cargo build -p bitwarden-wasm --target wasm32-unknown-unknown --release wasm-bindgen --target bundler --out-dir languages/js/wasm ./target/wasm32-unknown-unknown/release/bitwarden_wasm.wasm wasm-bindgen --target nodejs --out-dir languages/js/wasm/node ./target/wasm32-unknown-unknown/release/bitwarden_wasm.wasm fi From a3e2e188304e6034d8f45c051b706194259eb8f3 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 17:27:15 +0200 Subject: [PATCH 26/28] Fix tests --- .../src/client/client_settings.rs | 2 +- .../src/client_generator.rs | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/bitwarden-core/src/client/client_settings.rs b/crates/bitwarden-core/src/client/client_settings.rs index d82e5d93c..bd678d131 100644 --- a/crates/bitwarden-core/src/client/client_settings.rs +++ b/crates/bitwarden-core/src/client/client_settings.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; /// Defaults to /// /// ``` -/// # use bitwarden::{ClientSettings, DeviceType}; +/// # use bitwarden_core::{ClientSettings, DeviceType}; /// let settings = ClientSettings { /// identity_url: "https://identity.bitwarden.com".to_string(), /// api_url: "https://api.bitwarden.com".to_string(), diff --git a/crates/bitwarden-generators/src/client_generator.rs b/crates/bitwarden-generators/src/client_generator.rs index 310fe4ebc..e5bad6f29 100644 --- a/crates/bitwarden-generators/src/client_generator.rs +++ b/crates/bitwarden-generators/src/client_generator.rs @@ -21,8 +21,10 @@ impl<'a> ClientGenerator<'a> { /// # Examples /// /// ``` - /// use bitwarden::{Client, generators::PasswordGeneratorRequest, error::Result}; - /// async fn test() -> Result<()> { + /// use bitwarden_core::Client; + /// use bitwarden_generators::{ClientGeneratorExt, PassphraseError, PasswordGeneratorRequest}; + /// + /// async fn test() -> Result<(), PassphraseError> { /// let input = PasswordGeneratorRequest { /// lowercase: true, /// uppercase: true, @@ -49,8 +51,10 @@ impl<'a> ClientGenerator<'a> { /// # Examples /// /// ``` - /// use bitwarden::{Client, generators::PassphraseGeneratorRequest, error::Result}; - /// async fn test() -> Result<()> { + /// use bitwarden_core::Client; + /// use bitwarden_generators::{ClientGeneratorExt, PassphraseError, PassphraseGeneratorRequest}; + /// + /// async fn test() -> Result<(), PassphraseError> { /// let input = PassphraseGeneratorRequest { /// num_words: 4, /// ..Default::default() @@ -72,8 +76,10 @@ impl<'a> ClientGenerator<'a> { /// will use third-party services, which may require a specific setup or API key. /// /// ``` - /// use bitwarden::{Client, generators::{UsernameGeneratorRequest}, error::Result}; - /// async fn test() -> Result<()> { + /// use bitwarden_core::Client; + /// use bitwarden_generators::{ClientGeneratorExt, UsernameError, UsernameGeneratorRequest}; + /// + /// async fn test() -> Result<(), UsernameError> { /// let input = UsernameGeneratorRequest::Word { /// capitalize: true, /// include_number: true, From b1ef717571bffd5bf61790b85139bab46372dd25 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 24 Jun 2024 18:18:07 +0200 Subject: [PATCH 27/28] Cleanup cargo files --- crates/bitwarden-core/Cargo.toml | 4 +--- crates/bitwarden-core/src/error.rs | 2 +- crates/bitwarden-fido/Cargo.toml | 2 +- crates/bitwarden-send/Cargo.toml | 2 +- crates/bitwarden-vault/Cargo.toml | 3 +-- crates/bitwarden/Cargo.toml | 2 +- 6 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index a34ca1fa8..ba3ebbe68 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -14,8 +14,6 @@ repository.workspace = true license-file.workspace = true [features] -default = ["secrets"] - internal = [] # Internal testing methods no-memory-hardening = [ "bitwarden-crypto/no-memory-hardening", @@ -31,7 +29,7 @@ secrets = [] # Secrets manager API [dependencies] async-trait = ">=0.1.80, <0.2" -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-api-api = { workspace = true } bitwarden-api-identity = { workspace = true } bitwarden-crypto = { workspace = true } diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index 5e7f4338a..e4ca94a25 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -114,7 +114,7 @@ macro_rules! impl_bitwarden_error { impl_bitwarden_error!(ApiError); impl_bitwarden_error!(IdentityError); -pub type Result = std::result::Result; +pub(crate) type Result = std::result::Result; #[derive(Debug, Error)] #[error("The response received was missing a required field: {0}")] diff --git a/crates/bitwarden-fido/Cargo.toml b/crates/bitwarden-fido/Cargo.toml index de9ec79d5..12c2b6b1d 100644 --- a/crates/bitwarden-fido/Cargo.toml +++ b/crates/bitwarden-fido/Cargo.toml @@ -18,7 +18,7 @@ uniffi = ["dep:uniffi", "bitwarden-core/uniffi", "bitwarden-vault/uniffi"] [dependencies] async-trait = ">=0.1.80, <0.2" -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } bitwarden-vault = { workspace = true } diff --git a/crates/bitwarden-send/Cargo.toml b/crates/bitwarden-send/Cargo.toml index 9646ddcd9..bae76a5bf 100644 --- a/crates/bitwarden-send/Cargo.toml +++ b/crates/bitwarden-send/Cargo.toml @@ -21,7 +21,7 @@ uniffi = [ ] # Uniffi bindings [dependencies] -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-api-api = { workspace = true } bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } diff --git a/crates/bitwarden-vault/Cargo.toml b/crates/bitwarden-vault/Cargo.toml index b022796b1..e875e4c06 100644 --- a/crates/bitwarden-vault/Cargo.toml +++ b/crates/bitwarden-vault/Cargo.toml @@ -21,7 +21,7 @@ uniffi = [ ] # Uniffi bindings [dependencies] -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-api-api = { workspace = true } bitwarden-core = { workspace = true, features = ["internal"] } bitwarden-crypto = { workspace = true } @@ -43,7 +43,6 @@ uniffi = { version = "=0.27.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } [dev-dependencies] -bitwarden-core = { workspace = true, features = ["internal"] } tokio = { version = "1.36.0", features = ["rt", "macros"] } [lints] diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 2766a21ce..3bd1f02fa 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -35,7 +35,7 @@ uniffi = [ "bitwarden-send/uniffi", "bitwarden-vault/uniffi", ] # Uniffi bindings -secrets = ["dep:bitwarden-sm"] # Secrets manager API +secrets = ["bitwarden-core/secrets", "dep:bitwarden-sm"] # Secrets manager API [dependencies] bitwarden-api-api = { workspace = true } From 0059e79be205a0b363e05bc679bfad1d24fd9f02 Mon Sep 17 00:00:00 2001 From: Hinton Date: Tue, 25 Jun 2024 18:31:11 +0200 Subject: [PATCH 28/28] Fix android --- Cargo.lock | 1 + crates/bitwarden-exporters/uniffi.toml | 9 +++++++++ crates/bitwarden-uniffi/Cargo.toml | 1 + .../java/com/bitwarden/myapplication/MainActivity.kt | 6 +++--- 4 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 crates/bitwarden-exporters/uniffi.toml diff --git a/Cargo.lock b/Cargo.lock index 55266a08b..a1c0dbe4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -622,6 +622,7 @@ dependencies = [ "bitwarden", "bitwarden-core", "bitwarden-crypto", + "bitwarden-exporters", "bitwarden-fido", "bitwarden-generators", "bitwarden-send", diff --git a/crates/bitwarden-exporters/uniffi.toml b/crates/bitwarden-exporters/uniffi.toml new file mode 100644 index 000000000..7a57dfabd --- /dev/null +++ b/crates/bitwarden-exporters/uniffi.toml @@ -0,0 +1,9 @@ +[bindings.kotlin] +package_name = "com.bitwarden.exporters" +generate_immutable_records = true +android = true + +[bindings.swift] +ffi_module_name = "BitwardenExportersFFI" +module_name = "BitwardenExporters" +generate_immutable_records = true diff --git a/crates/bitwarden-uniffi/Cargo.toml b/crates/bitwarden-uniffi/Cargo.toml index f5c1230c0..2b2ecd11e 100644 --- a/crates/bitwarden-uniffi/Cargo.toml +++ b/crates/bitwarden-uniffi/Cargo.toml @@ -22,6 +22,7 @@ async-trait = "0.1.80" bitwarden = { workspace = true, features = ["internal", "uniffi"] } bitwarden-core = { workspace = true, features = ["uniffi"] } bitwarden-crypto = { workspace = true, features = ["uniffi"] } +bitwarden-exporters = { workspace = true, features = ["uniffi"] } bitwarden-fido = { workspace = true, features = ["uniffi"] } bitwarden-generators = { workspace = true, features = ["uniffi"] } bitwarden-send = { workspace = true, features = ["uniffi"] } diff --git a/languages/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt b/languages/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt index 889079692..c65e0d3c6 100644 --- a/languages/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt +++ b/languages/kotlin/app/src/main/java/com/bitwarden/myapplication/MainActivity.kt @@ -24,9 +24,9 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.FragmentActivity import com.bitwarden.core.DateTime import com.bitwarden.vault.Folder -import com.bitwarden.bitwarden.InitOrgCryptoRequest -import com.bitwarden.bitwarden.InitUserCryptoMethod -import com.bitwarden.bitwarden.InitUserCryptoRequest +import com.bitwarden.core.InitOrgCryptoRequest +import com.bitwarden.core.InitUserCryptoMethod +import com.bitwarden.core.InitUserCryptoRequest import com.bitwarden.core.Uuid import com.bitwarden.crypto.HashPurpose import com.bitwarden.crypto.Kdf