Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-11764] Implement account switching and sdk initialization #1116

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .editorconfig
coroiu marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ insert_final_newline = true
indent_style = space
indent_size = 2

[*.{ts}]
[*.ts]
quote_type = single

[*.{rs}]
[*.rs]
indent_style = space
indent_size = 4

[*.{kt,java,xml,gradle}]
indent_style = space
indent_size = 4

[*.{xml}]
[*.xml]
# VS Code XML extension removes the final newline
insert_final_newline = false
7 changes: 7 additions & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions crates/bitwarden-core/src/mobile/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "wasm")]
use {tsify_next::Tsify, wasm_bindgen::prelude::*};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, I just discovered now thanks to this that you can use a top level {} block in a use statement, neat!


use crate::{
client::{encryption_settings::EncryptionSettingsError, LoginMethod, UserLoginMethod},
Expand All @@ -16,6 +18,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 21 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L21

Added line #L21 was not covered by tests
pub struct InitUserCryptoRequest {
/// The user's KDF parameters, as received from the prelogin request
pub kdf_params: Kdf,
Expand All @@ -30,6 +33,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 36 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L36

Added line #L36 was not covered by tests
pub enum InitUserCryptoMethod {
Password {
/// The user's master password
Expand Down Expand Up @@ -73,6 +77,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 80 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L80

Added line #L80 was not covered by tests
pub enum AuthRequestMethod {
UserKey {
/// User Key protected by the private key provided in `AuthRequestResponse`.
Expand Down Expand Up @@ -185,6 +190,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 193 in crates/bitwarden-core/src/mobile/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-core/src/mobile/crypto.rs#L193

Added line #L193 was not covered by tests
pub struct InitOrgCryptoRequest {
/// The encryption keys for all the organizations the user is a part of
pub organization_keys: HashMap<uuid::Uuid, AsymmetricEncString>,
Expand Down
3 changes: 3 additions & 0 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ keywords.workspace = true

[features]
default = []
wasm = ["dep:tsify-next", "dep:wasm-bindgen"] # WASM support

uniffi = ["dep:uniffi"] # Uniffi bindings
no-memory-hardening = [] # Disable memory hardening features
Expand Down Expand Up @@ -42,8 +43,10 @@ sha1 = ">=0.10.5, <0.11"
sha2 = ">=0.10.6, <0.11"
subtle = ">=2.5.0, <3.0"
thiserror = { workspace = true }
tsify-next = { workspace = true, optional = true }
uniffi = { workspace = true, optional = true }
uuid = { workspace = true }
wasm-bindgen = { workspace = true, optional = true }
zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] }

[dev-dependencies]
Expand Down
7 changes: 6 additions & 1 deletion crates/bitwarden-crypto/src/enc_string/asymmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ use crate::{
rsa::encrypt_rsa2048_oaep_sha1,
AsymmetricCryptoKey, AsymmetricEncryptable, KeyDecryptable,
};

// This module is a workaround to avoid deprecated warnings that come from the ZeroizeOnDrop
// macro expansion
#[allow(deprecated)]
mod internal {
#[cfg(feature = "wasm")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_CUSTOM_TYPES: &'static str = r#"
export type AsymmetricEncString = string;
"#;
Comment on lines +18 to +22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a uniffi_support.rs file, would it make sense to add something similar for these custom logics? Or should we encourage lifting in the uniffi logic to where it's needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added custom_types.rs which is inspired by that uniffi file, but I think adding the types where they are defined is a preferred approach. It's just that we sometimes use external type and so I needed both approaches


/// # Encrypted string primitive
///
/// [AsymmetricEncString] is a Bitwarden specific primitive that represents an asymmetrically
Expand Down
6 changes: 6 additions & 0 deletions crates/bitwarden-crypto/src/enc_string/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ use crate::{
KeyDecryptable, KeyEncryptable, LocateKey, SymmetricCryptoKey,
};

#[cfg(feature = "wasm")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_CUSTOM_TYPES: &'static str = r#"
export type EncString = string;
"#;

/// # Encrypted string primitive
///
/// [EncString] is a Bitwarden specific primitive that represents a symmetrically encrypted string.
Expand Down
3 changes: 3 additions & 0 deletions crates/bitwarden-crypto/src/keys/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use rand::Rng;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[cfg(feature = "wasm")]
use {tsify_next::Tsify, wasm_bindgen::prelude::*};

use super::utils::{derive_kdf_key, stretch_kdf_key};
use crate::{util, CryptoError, EncString, KeyDecryptable, Result, SymmetricCryptoKey, UserKey};
Expand All @@ -16,6 +18,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 21 in crates/bitwarden-crypto/src/keys/master_key.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/master_key.rs#L21

Added line #L21 was not covered by tests
pub enum Kdf {
PBKDF2 {
iterations: NonZeroU32,
Expand Down
10 changes: 5 additions & 5 deletions crates/bitwarden-napi/src-ts/bitwarden_client/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as rust from "../../binding";
import { LogLevel } from "../../binding";
import * as rust from '../../binding';
import { LogLevel } from '../../binding';
import {
Convert,
ClientSettings,
Expand All @@ -11,19 +11,19 @@ import {
SecretsDeleteResponse,
SecretsResponse,
SecretsSyncResponse,
} from "./schemas";
} from './schemas';

function handleResponse<T>(response: {
success: boolean;
errorMessage?: string | null;
data?: T | null;
}): T {
if (!response.success) {
throw new Error(response.errorMessage || "");
throw new Error(response.errorMessage || '');
}

if (response.data === null) {
throw new Error(response.errorMessage || "SDK response data is null");
throw new Error(response.errorMessage || 'SDK response data is null');
}

return response.data as T;
Expand Down
6 changes: 3 additions & 3 deletions crates/bitwarden-napi/src-ts/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from "./bitwarden_client/index";
export * from "./bitwarden_client/schemas";
export { LogLevel } from "../binding";
export * from './bitwarden_client/index';
export * from './bitwarden_client/schemas';
export { LogLevel } from '../binding';
3 changes: 3 additions & 0 deletions crates/bitwarden-vault/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ uniffi = [
"bitwarden-crypto/uniffi",
"dep:uniffi",
] # Uniffi bindings
wasm = ["dep:tsify-next", "dep:wasm-bindgen"] # WASM support

[dependencies]
base64 = ">=0.22.1, <0.23"
Expand All @@ -38,6 +39,8 @@ sha2 = ">=0.10.6, <0.11"
thiserror = { workspace = true }
uniffi = { version = "=0.28.1", optional = true }
uuid = { workspace = true }
tsify-next = { workspace = true, optional = true }
wasm-bindgen = { workspace = true, optional = true }

[dev-dependencies]
tokio = { workspace = true, features = ["rt"] }
Expand Down
4 changes: 4 additions & 0 deletions crates/bitwarden-vault/src/folder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[cfg(feature = "wasm")]
use {tsify_next::Tsify, wasm_bindgen::prelude::*};

use crate::VaultParseError;

#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 18 in crates/bitwarden-vault/src/folder.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/folder.rs#L18

Added line #L18 was not covered by tests
pub struct Folder {
id: Option<Uuid>,
name: EncString,
Expand All @@ -22,6 +25,7 @@
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]

Check warning on line 28 in crates/bitwarden-vault/src/folder.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-vault/src/folder.rs#L28

Added line #L28 was not covered by tests
pub struct FolderView {
pub id: Option<Uuid>,
pub name: String,
Expand Down
3 changes: 3 additions & 0 deletions crates/bitwarden-wasm-internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ crate-type = ["cdylib"]

[dependencies]
bitwarden = { workspace = true, features = ["internal", "wasm"] }
bitwarden-core = { workspace = true, features = ["wasm"] }
bitwarden-crypto = { workspace = true, features = ["wasm"] }
bitwarden-vault = { workspace = true, features = ["wasm"] }
console_error_panic_hook = "0.1.7"
console_log = { version = "1.0.0", features = ["color"] }
js-sys = "0.3.68"
Expand Down
12 changes: 11 additions & 1 deletion crates/bitwarden-wasm-internal/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use log::{set_max_level, Level};
use wasm_bindgen::prelude::*;

use crate::{vault::ClientVault, ClientCrypto};

#[wasm_bindgen]
pub enum LogLevel {
Trace,
Expand All @@ -27,7 +29,7 @@
// Rc<...> is to avoid needing to take ownership of the Client during our async run_command
// function https://github.com/rustwasm/wasm-bindgen/issues/2195#issuecomment-799588401
#[wasm_bindgen]
pub struct BitwardenClient(Rc<Client>);
pub struct BitwardenClient(pub(crate) Rc<Client>);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct BitwardenClient(pub(crate) Rc<Client>);
pub struct BitwardenClient(Rc<Client>);

Nit: This inner value is only used on it's own impl as far as I know, so we don't need it to be pub(crate)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used when creating it, but I can just create a new function instead
image


#[wasm_bindgen]
impl BitwardenClient {
Expand All @@ -54,4 +56,12 @@

res.text().await.map_err(|e| e.to_string())
}

pub fn crypto(&self) -> ClientCrypto {
ClientCrypto(self.0.clone())
}

Check warning on line 62 in crates/bitwarden-wasm-internal/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/client.rs#L60-L62

Added lines #L60 - L62 were not covered by tests

pub fn vault(&self) -> ClientVault {
ClientVault(self.0.clone())
}

Check warning on line 66 in crates/bitwarden-wasm-internal/src/client.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/client.rs#L64-L66

Added lines #L64 - L66 were not covered by tests
}
37 changes: 37 additions & 0 deletions crates/bitwarden-wasm-internal/src/crypto.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use std::rc::Rc;

use bitwarden::{
mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest},
Client,
};
use wasm_bindgen::prelude::*;

use crate::error::Result;

#[wasm_bindgen]
pub struct ClientCrypto(pub(crate) Rc<Client>);

#[wasm_bindgen]

Check warning on line 14 in crates/bitwarden-wasm-internal/src/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/crypto.rs#L14

Added line #L14 was not covered by tests
impl ClientCrypto {
/// Initialization method for the user crypto. Needs to be called before any other crypto
/// operations.
pub async fn initialize_user_crypto(&self, req: InitUserCryptoRequest) -> Result<()> {
Ok(self
.0
.crypto()
.initialize_user_crypto(req)
.await
.map_err(bitwarden_core::Error::EncryptionSettings)?)
coroiu marked this conversation as resolved.
Show resolved Hide resolved
}

Check warning on line 25 in crates/bitwarden-wasm-internal/src/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/crypto.rs#L18-L25

Added lines #L18 - L25 were not covered by tests

/// Initialization method for the organization crypto. Needs to be called after
/// `initialize_user_crypto` but before any other crypto operations.
pub async fn initialize_org_crypto(&self, req: InitOrgCryptoRequest) -> Result<()> {
Ok(self
.0
.crypto()
.initialize_org_crypto(req)
.await
.map_err(bitwarden_core::Error::EncryptionSettings)?)
}

Check warning on line 36 in crates/bitwarden-wasm-internal/src/crypto.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/crypto.rs#L29-L36

Added lines #L29 - L36 were not covered by tests
}
22 changes: 22 additions & 0 deletions crates/bitwarden-wasm-internal/src/custom_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// This file contains custom TypeScript for types defined by external crates.
/// Everything in the string below is appended to the generated TypeScript definition file.
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
const TS_CUSTOM_TYPES: &'static str = r#"
export type Uuid = string;

/**
* RFC3339 compliant date-time string.
* @typeParam T - Not used in JavaScript.
*/
export type DateTime<T = unknown> = string;

/**
* UTC date-time string. Not used in JavaScript.
*/
export type Utc = unknown;

/**
* An integer that is known not to equal zero.
*/
export type NonZeroU32 = number;
"#;
11 changes: 11 additions & 0 deletions crates/bitwarden-wasm-internal/src/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Error thrown by the WASM module.
* @param {string} message - Error message.
* @extends Error
*/
export class WasmError extends Error {
constructor(message) {
super(message);
this.name = "WasmError";
}
}
33 changes: 33 additions & 0 deletions crates/bitwarden-wasm-internal/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use wasm_bindgen::prelude::*;

// Importing an error class defined in JavaScript instead of defining it in Rust
// allows us to extend the `Error` class. It also provides much better console output.
#[wasm_bindgen(module = "/src/error.js")]
extern "C" {
type WasmError;

#[wasm_bindgen(constructor)]
fn new(message: String) -> WasmError;
}

pub type Result<T, E = Error> = std::result::Result<T, E>;

pub struct Error(bitwarden::error::Error);

impl From<bitwarden::error::Error> for Error {
fn from(error: bitwarden::error::Error) -> Self {
Self(error)
}

Check warning on line 20 in crates/bitwarden-wasm-internal/src/error.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/error.rs#L18-L20

Added lines #L18 - L20 were not covered by tests
}

impl From<bitwarden::Error> for Error {
fn from(error: bitwarden::Error) -> Self {
Self(error.into())
}

Check warning on line 26 in crates/bitwarden-wasm-internal/src/error.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/error.rs#L24-L26

Added lines #L24 - L26 were not covered by tests
}

impl From<Error> for JsValue {
fn from(error: Error) -> Self {
WasmError::new(error.0.to_string()).into()
}

Check warning on line 32 in crates/bitwarden-wasm-internal/src/error.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-wasm-internal/src/error.rs#L30-L32

Added lines #L30 - L32 were not covered by tests
}
8 changes: 8 additions & 0 deletions crates/bitwarden-wasm-internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
mod client;
mod crypto;
mod custom_types;
mod error;
mod vault;

pub use client::BitwardenClient;
pub use crypto::ClientCrypto;
pub use vault::{folders::ClientFolders, ClientVault};
Loading
Loading