From 4b1d6a1aecda40ccbe6268dfe8c3fb21d5124135 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Fri, 21 Jun 2024 13:30:12 -0400 Subject: [PATCH 01/11] [SM-1287] Refactor out command logic from main.rs in bws (#809) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎟ī¸ Tracking [SM-1287](https://bitwarden.atlassian.net/browse/SM-1287) ## 📔 Objective The goal of this PR is to refactor `bws/src/main.rs` and the `process_commands()` function. This PR moves the actual CLI interaction for individual commands to the `command` module and appropriate sub-modules. There are plenty of other additions and changes to be made, but I'm trying to keep this PR a clean refactor and we can address other items in separate PR's. Deprecation of the legacy CLI commands will happen in [SM-1175](https://bitwarden.atlassian.net/browse/SM-1175). ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## đŸĻŽ Reviewer guidelines - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹī¸ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or ⚠ī¸ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or â™ģī¸ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes [SM-1287]: https://bitwarden.atlassian.net/browse/SM-1287?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [SM-1175]: https://bitwarden.atlassian.net/browse/SM-1175?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- crates/bws/src/command/mod.rs | 59 +++++++ crates/bws/src/command/project.rs | 116 +++++++++++++ crates/bws/src/command/secret.rs | 163 +++++++++++++++++++ crates/bws/src/config.rs | 4 +- crates/bws/src/main.rs | 260 ++++++------------------------ crates/bws/src/render.rs | 26 ++- 6 files changed, 406 insertions(+), 222 deletions(-) create mode 100644 crates/bws/src/command/mod.rs create mode 100644 crates/bws/src/command/project.rs create mode 100644 crates/bws/src/command/secret.rs diff --git a/crates/bws/src/command/mod.rs b/crates/bws/src/command/mod.rs new file mode 100644 index 000000000..0fe257c42 --- /dev/null +++ b/crates/bws/src/command/mod.rs @@ -0,0 +1,59 @@ +pub(crate) mod project; +pub(crate) mod secret; + +use std::{path::PathBuf, str::FromStr}; + +use bitwarden::auth::AccessToken; +use clap::CommandFactory; +use clap_complete::Shell; +use color_eyre::eyre::{bail, Result}; + +use crate::{config, Cli, ProfileKey}; + +pub(crate) fn completions(shell: Option) -> Result<()> { + let Some(shell) = shell.or_else(Shell::from_env) else { + bail!("Couldn't autodetect a valid shell. Run `bws completions --help` for more info."); + }; + + let mut cmd = Cli::command(); + let name = cmd.get_name().to_string(); + clap_complete::generate(shell, &mut cmd, name, &mut std::io::stdout()); + + Ok(()) +} + +pub(crate) fn config( + name: Option, + value: Option, + delete: bool, + profile: Option, + access_token: Option, + config_file: Option, +) -> Result<()> { + let profile = if let Some(profile) = profile { + profile + } else if let Some(access_token) = access_token { + AccessToken::from_str(&access_token)? + .access_token_id + .to_string() + } else { + String::from("default") + }; + + if delete { + config::delete_profile(config_file.as_deref(), profile)?; + println!("Profile deleted successfully!"); + } else { + let (name, value) = match (name, value) { + (None, None) => bail!("Missing `name` and `value`"), + (None, Some(_)) => bail!("Missing `value`"), + (Some(_), None) => bail!("Missing `name`"), + (Some(name), Some(value)) => (name, value), + }; + + config::update_profile(config_file.as_deref(), profile, name, value)?; + println!("Profile updated successfully!"); + }; + + Ok(()) +} diff --git a/crates/bws/src/command/project.rs b/crates/bws/src/command/project.rs new file mode 100644 index 000000000..72060fdf4 --- /dev/null +++ b/crates/bws/src/command/project.rs @@ -0,0 +1,116 @@ +use bitwarden::{ + secrets_manager::projects::{ + ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsDeleteRequest, + ProjectsListRequest, + }, + Client, +}; +use color_eyre::eyre::{bail, Result}; +use uuid::Uuid; + +use crate::render::{serialize_response, OutputSettings}; + +pub(crate) async fn list( + client: Client, + organization_id: Uuid, + output_settings: OutputSettings, +) -> Result<()> { + let projects = client + .projects() + .list(&ProjectsListRequest { organization_id }) + .await? + .data; + serialize_response(projects, output_settings); + + Ok(()) +} + +pub(crate) async fn get( + client: Client, + project_id: Uuid, + output_settings: OutputSettings, +) -> Result<()> { + let project = client + .projects() + .get(&ProjectGetRequest { id: project_id }) + .await?; + serialize_response(project, output_settings); + + Ok(()) +} + +pub(crate) async fn create( + client: Client, + organization_id: Uuid, + name: String, + output_settings: OutputSettings, +) -> Result<()> { + let project = client + .projects() + .create(&ProjectCreateRequest { + organization_id, + name, + }) + .await?; + serialize_response(project, output_settings); + + Ok(()) +} + +pub(crate) async fn edit( + client: Client, + organization_id: Uuid, + project_id: Uuid, + name: String, + output_settings: OutputSettings, +) -> Result<()> { + let project = client + .projects() + .update(&ProjectPutRequest { + id: project_id, + organization_id, + name, + }) + .await?; + serialize_response(project, output_settings); + + Ok(()) +} + +pub(crate) async fn delete(client: Client, project_ids: Vec) -> Result<()> { + let count = project_ids.len(); + + let result = client + .projects() + .delete(ProjectsDeleteRequest { ids: project_ids }) + .await?; + + let projects_failed: Vec<(Uuid, String)> = result + .data + .into_iter() + .filter_map(|r| r.error.map(|e| (r.id, e))) + .collect(); + let deleted_projects = count - projects_failed.len(); + + match deleted_projects { + 2.. => println!("{} projects deleted successfully.", deleted_projects), + 1 => println!("{} project deleted successfully.", deleted_projects), + _ => (), + } + + match projects_failed.len() { + 2.. => eprintln!("{} projects had errors:", projects_failed.len()), + 1 => eprintln!("{} project had an error:", projects_failed.len()), + _ => (), + } + + for project in &projects_failed { + eprintln!("{}: {}", project.0, project.1); + } + + if !projects_failed.is_empty() { + bail!("Errors when attempting to delete projects."); + } + + Ok(()) +} diff --git a/crates/bws/src/command/secret.rs b/crates/bws/src/command/secret.rs new file mode 100644 index 000000000..30613016d --- /dev/null +++ b/crates/bws/src/command/secret.rs @@ -0,0 +1,163 @@ +use bitwarden::{ + secrets_manager::secrets::{ + SecretCreateRequest, SecretGetRequest, SecretIdentifiersByProjectRequest, + SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, + }, + Client, +}; +use color_eyre::eyre::{bail, Result}; +use uuid::Uuid; + +use crate::render::{serialize_response, OutputSettings}; + +#[derive(Debug)] +pub(crate) struct SecretCreateCommandModel { + pub(crate) key: String, + pub(crate) value: String, + pub(crate) note: Option, + pub(crate) project_id: Uuid, +} + +#[derive(Debug)] +pub(crate) struct SecretEditCommandModel { + pub(crate) id: Uuid, + pub(crate) key: Option, + pub(crate) value: Option, + pub(crate) note: Option, + pub(crate) project_id: Option, +} + +pub(crate) async fn list( + client: Client, + organization_id: Uuid, + project_id: Option, + output_settings: OutputSettings, +) -> Result<()> { + let res = if let Some(project_id) = project_id { + client + .secrets() + .list_by_project(&SecretIdentifiersByProjectRequest { project_id }) + .await? + } else { + client + .secrets() + .list(&SecretIdentifiersRequest { organization_id }) + .await? + }; + + let secret_ids = res.data.into_iter().map(|e| e.id).collect(); + let secrets = client + .secrets() + .get_by_ids(SecretsGetRequest { ids: secret_ids }) + .await? + .data; + serialize_response(secrets, output_settings); + + Ok(()) +} + +pub(crate) async fn get( + client: Client, + secret_id: Uuid, + output_settings: OutputSettings, +) -> Result<()> { + let secret = client + .secrets() + .get(&SecretGetRequest { id: secret_id }) + .await?; + serialize_response(secret, output_settings); + + Ok(()) +} + +pub(crate) async fn create( + client: Client, + organization_id: Uuid, + secret: SecretCreateCommandModel, + output_settings: OutputSettings, +) -> Result<()> { + let secret = client + .secrets() + .create(&SecretCreateRequest { + organization_id, + key: secret.key, + value: secret.value, + note: secret.note.unwrap_or_default(), + project_ids: Some(vec![secret.project_id]), + }) + .await?; + serialize_response(secret, output_settings); + + Ok(()) +} + +pub(crate) async fn edit( + client: Client, + organization_id: Uuid, + secret: SecretEditCommandModel, + output_settings: OutputSettings, +) -> Result<()> { + let old_secret = client + .secrets() + .get(&SecretGetRequest { id: secret.id }) + .await?; + + let new_secret = client + .secrets() + .update(&SecretPutRequest { + id: secret.id, + organization_id, + key: secret.key.unwrap_or(old_secret.key), + value: secret.value.unwrap_or(old_secret.value), + note: secret.note.unwrap_or(old_secret.note), + project_ids: match secret.project_id { + Some(id) => Some(vec![id]), + None => match old_secret.project_id { + Some(id) => Some(vec![id]), + None => bail!("Editing a secret requires a project_id."), + }, + }, + }) + .await?; + serialize_response(new_secret, output_settings); + + Ok(()) +} + +pub(crate) async fn delete(client: Client, secret_ids: Vec) -> Result<()> { + let count = secret_ids.len(); + + let result = client + .secrets() + .delete(SecretsDeleteRequest { ids: secret_ids }) + .await?; + + let secrets_failed: Vec<(Uuid, String)> = result + .data + .into_iter() + .filter_map(|r| r.error.map(|e| (r.id, e))) + .collect(); + let deleted_secrets = count - secrets_failed.len(); + + match deleted_secrets { + 2.. => println!("{} secrets deleted successfully.", deleted_secrets), + 1 => println!("{} secret deleted successfully.", deleted_secrets), + _ => (), + } + + match secrets_failed.len() { + 2.. => eprintln!("{} secrets had errors:", secrets_failed.len()), + 1 => eprintln!("{} secret had an error:", secrets_failed.len()), + _ => (), + } + + for secret in &secrets_failed { + eprintln!("{}: {}", secret.0, secret.1); + } + + if !secrets_failed.is_empty() { + bail!("Errors when attempting to delete secrets."); + } + + Ok(()) +} diff --git a/crates/bws/src/config.rs b/crates/bws/src/config.rs index 9756704f4..f769bb6da 100644 --- a/crates/bws/src/config.rs +++ b/crates/bws/src/config.rs @@ -129,7 +129,7 @@ impl Profile { return Ok(format!("{base}/api")); } - bail!("Profile has no `server_base` or `server_api`") + bail!("Profile has no `server_base` or `server_api`"); } pub(crate) fn identity_url(&self) -> Result { @@ -141,7 +141,7 @@ impl Profile { return Ok(format!("{base}/identity")); } - bail!("Profile has no `server_base` or `server_identity`") + bail!("Profile has no `server_base` or `server_identity`"); } } diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index bbd909eff..be1ea2bd4 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -1,32 +1,23 @@ -use std::{path::PathBuf, process, str::FromStr}; +use std::{path::PathBuf, str::FromStr}; use bitwarden::{ auth::{login::AccessTokenLoginRequest, AccessToken}, - secrets_manager::{ - projects::{ - ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsDeleteRequest, - ProjectsListRequest, - }, - secrets::{ - SecretCreateRequest, SecretGetRequest, SecretIdentifiersByProjectRequest, - SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, - }, - }, ClientSettings, }; use bitwarden_cli::install_color_eyre; use clap::{CommandFactory, Parser}; -use clap_complete::Shell; use color_eyre::eyre::{bail, Result}; +use command::secret::{SecretCreateCommandModel, SecretEditCommandModel}; use log::error; -use uuid::Uuid; +use render::OutputSettings; mod cli; +mod command; mod config; mod render; mod state; -use crate::{cli::*, render::serialize_response}; +use crate::cli::*; #[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { @@ -51,47 +42,21 @@ async fn process_commands() -> Result<()> { // These commands don't require authentication, so we process them first match command { Commands::Completions { shell } => { - let Some(shell) = shell.or_else(Shell::from_env) else { - eprintln!("Couldn't autodetect a valid shell. Run `bws completions --help` for more info."); - std::process::exit(1); - }; - - let mut cmd = Cli::command(); - let name = cmd.get_name().to_string(); - clap_complete::generate(shell, &mut cmd, name, &mut std::io::stdout()); - return Ok(()); + return command::completions(shell); } Commands::Config { name, value, delete, } => { - let profile = if let Some(profile) = cli.profile { - profile - } else if let Some(access_token) = cli.access_token { - AccessToken::from_str(&access_token)? - .access_token_id - .to_string() - } else { - String::from("default") - }; - - if delete { - config::delete_profile(cli.config_file.as_deref(), profile)?; - println!("Profile deleted successfully!"); - } else { - let (name, value) = match (name, value) { - (None, None) => bail!("Missing `name` and `value`"), - (None, Some(_)) => bail!("Missing `value`"), - (Some(_), None) => bail!("Missing `name`"), - (Some(name), Some(value)) => (name, value), - }; - - config::update_profile(cli.config_file.as_deref(), profile, name, value)?; - println!("Profile updated successfully!"); - }; - - return Ok(()); + return command::config( + name, + value, + delete, + cli.profile, + cli.access_token, + cli.config_file, + ); } _ => (), } @@ -144,6 +109,8 @@ async fn process_commands() -> Result<()> { } }; + let output_settings = OutputSettings::new(cli.output, color); + // And finally we process all the commands which require authentication match command { Commands::Project { @@ -151,43 +118,21 @@ async fn process_commands() -> Result<()> { } | Commands::List { cmd: ListCommand::Projects, - } => { - let projects = client - .projects() - .list(&ProjectsListRequest { organization_id }) - .await? - .data; - serialize_response(projects, cli.output, color); - } + } => command::project::list(client, organization_id, output_settings).await, Commands::Project { cmd: ProjectCommand::Get { project_id }, } | Commands::Get { cmd: GetCommand::Project { project_id }, - } => { - let project = client - .projects() - .get(&ProjectGetRequest { id: project_id }) - .await?; - serialize_response(project, cli.output, color); - } + } => command::project::get(client, project_id, output_settings).await, Commands::Project { cmd: ProjectCommand::Create { name }, } | Commands::Create { cmd: CreateCommand::Project { name }, - } => { - let project = client - .projects() - .create(&ProjectCreateRequest { - organization_id, - name, - }) - .await?; - serialize_response(project, cli.output, color); - } + } => command::project::create(client, organization_id, name, output_settings).await, Commands::Project { cmd: ProjectCommand::Edit { project_id, name }, @@ -195,15 +140,7 @@ async fn process_commands() -> Result<()> { | Commands::Edit { cmd: EditCommand::Project { project_id, name }, } => { - let project = client - .projects() - .update(&ProjectPutRequest { - id: project_id, - organization_id, - name, - }) - .await?; - serialize_response(project, cli.output, color); + command::project::edit(client, organization_id, project_id, name, output_settings).await } Commands::Project { @@ -211,81 +148,21 @@ async fn process_commands() -> Result<()> { } | Commands::Delete { cmd: DeleteCommand::Project { project_ids }, - } => { - let count = project_ids.len(); - - let result = client - .projects() - .delete(ProjectsDeleteRequest { ids: project_ids }) - .await?; - - let projects_failed: Vec<(Uuid, String)> = result - .data - .into_iter() - .filter_map(|r| r.error.map(|e| (r.id, e))) - .collect(); - let deleted_projects = count - projects_failed.len(); - - if deleted_projects > 1 { - println!("{} projects deleted successfully.", deleted_projects); - } else if deleted_projects == 1 { - println!("{} project deleted successfully.", deleted_projects); - } - - if projects_failed.len() > 1 { - eprintln!("{} projects had errors:", projects_failed.len()); - } else if projects_failed.len() == 1 { - eprintln!("{} project had an error:", projects_failed.len()); - } - - for project in &projects_failed { - eprintln!("{}: {}", project.0, project.1); - } - - if !projects_failed.is_empty() { - process::exit(1); - } - } + } => command::project::delete(client, project_ids).await, Commands::Secret { cmd: SecretCommand::List { project_id }, } | Commands::List { cmd: ListCommand::Secrets { project_id }, - } => { - let res = if let Some(project_id) = project_id { - client - .secrets() - .list_by_project(&SecretIdentifiersByProjectRequest { project_id }) - .await? - } else { - client - .secrets() - .list(&SecretIdentifiersRequest { organization_id }) - .await? - }; - - let secret_ids = res.data.into_iter().map(|e| e.id).collect(); - let secrets = client - .secrets() - .get_by_ids(SecretsGetRequest { ids: secret_ids }) - .await? - .data; - serialize_response(secrets, cli.output, color); - } + } => command::secret::list(client, organization_id, project_id, output_settings).await, Commands::Secret { cmd: SecretCommand::Get { secret_id }, } | Commands::Get { cmd: GetCommand::Secret { secret_id }, - } => { - let secret = client - .secrets() - .get(&SecretGetRequest { id: secret_id }) - .await?; - serialize_response(secret, cli.output, color); - } + } => command::secret::get(client, secret_id, output_settings).await, Commands::Secret { cmd: @@ -305,17 +182,18 @@ async fn process_commands() -> Result<()> { project_id, }, } => { - let secret = client - .secrets() - .create(&SecretCreateRequest { - organization_id, + command::secret::create( + client, + organization_id, + SecretCreateCommandModel { key, value, - note: note.unwrap_or_default(), - project_ids: Some(vec![project_id]), - }) - .await?; - serialize_response(secret, cli.output, color); + note, + project_id, + }, + output_settings, + ) + .await } Commands::Secret { @@ -338,29 +216,19 @@ async fn process_commands() -> Result<()> { project_id, }, } => { - let old_secret = client - .secrets() - .get(&SecretGetRequest { id: secret_id }) - .await?; - - let secret = client - .secrets() - .update(&SecretPutRequest { + command::secret::edit( + client, + organization_id, + SecretEditCommandModel { id: secret_id, - organization_id, - key: key.unwrap_or(old_secret.key), - value: value.unwrap_or(old_secret.value), - note: note.unwrap_or(old_secret.note), - project_ids: match project_id { - Some(id) => Some(vec![id]), - None => match old_secret.project_id { - Some(id) => Some(vec![id]), - None => bail!("Editing a secret requires a project_id."), - }, - }, - }) - .await?; - serialize_response(secret, cli.output, color); + key, + value, + note, + project_id, + }, + output_settings, + ) + .await } Commands::Secret { @@ -368,48 +236,12 @@ async fn process_commands() -> Result<()> { } | Commands::Delete { cmd: DeleteCommand::Secret { secret_ids }, - } => { - let count = secret_ids.len(); - - let result = client - .secrets() - .delete(SecretsDeleteRequest { ids: secret_ids }) - .await?; - - let secrets_failed: Vec<(Uuid, String)> = result - .data - .into_iter() - .filter_map(|r| r.error.map(|e| (r.id, e))) - .collect(); - let deleted_secrets = count - secrets_failed.len(); - - if deleted_secrets > 1 { - println!("{} secrets deleted successfully.", deleted_secrets); - } else if deleted_secrets == 1 { - println!("{} secret deleted successfully.", deleted_secrets); - } - - if secrets_failed.len() > 1 { - eprintln!("{} secrets had errors:", secrets_failed.len()); - } else if secrets_failed.len() == 1 { - eprintln!("{} secret had an error:", secrets_failed.len()); - } - - for secret in &secrets_failed { - eprintln!("{}: {}", secret.0, secret.1); - } - - if !secrets_failed.is_empty() { - process::exit(1); - } - } + } => command::secret::delete(client, secret_ids).await, Commands::Config { .. } | Commands::Completions { .. } => { unreachable!() } } - - Ok(()) } fn get_config_profile( diff --git a/crates/bws/src/render.rs b/crates/bws/src/render.rs index 219e72b68..7b286b511 100644 --- a/crates/bws/src/render.rs +++ b/crates/bws/src/render.rs @@ -8,23 +8,33 @@ use crate::cli::Output; const ASCII_HEADER_ONLY: &str = " -- "; +pub(crate) struct OutputSettings { + pub(crate) output: Output, + pub(crate) color: Color, +} + +impl OutputSettings { + pub(crate) fn new(output: Output, color: Color) -> Self { + OutputSettings { output, color } + } +} + pub(crate) fn serialize_response, const N: usize>( data: T, - output: Output, - color: Color, + output_settings: OutputSettings, ) { - match output { + match output_settings.output { Output::JSON => { let mut text = serde_json::to_string_pretty(&data).expect("Serialize should be infallible"); // Yaml/table/tsv serializations add a newline at the end, so we do the same here for // consistency text.push('\n'); - pretty_print("json", &text, color); + pretty_print("json", &text, output_settings.color); } Output::YAML => { let text = serde_yaml::to_string(&data).expect("Serialize should be infallible"); - pretty_print("yaml", &text, color); + pretty_print("yaml", &text, output_settings.color); } Output::Env => { let valid_key_regex = @@ -50,7 +60,11 @@ pub(crate) fn serialize_response, const N: usiz )); } - pretty_print("sh", &format!("{}\n", text.join("\n")), color); + pretty_print( + "sh", + &format!("{}\n", text.join("\n")), + output_settings.color, + ); } Output::Table => { let mut table = Table::new(); From 72dd93b7c142f0f93594d6dbd99d7f50967bc9a6 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 24 Jun 2024 12:20:41 +0200 Subject: [PATCH 02/11] Change access code generation to use alphanumerical (#853) Currently auth requests uses the password generator to generate a 25 character password. Since we're shuffling around code for #798 this won't be possible much longer. This PR adds a `generate_random_alphanumeric` to the `bitwarden_crypto` crate which generates a cryptographically secure random alphanumerical string that can be used instead. --- crates/bitwarden-crypto/src/lib.rs | 3 +-- crates/bitwarden-crypto/src/util.rs | 10 +++++++++- crates/bitwarden/src/auth/auth_request.rs | 13 +++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs index 3f54dec87..4c71b0029 100644 --- a/crates/bitwarden-crypto/src/lib.rs +++ b/crates/bitwarden-crypto/src/lib.rs @@ -76,9 +76,8 @@ pub use keys::*; mod rsa; pub use crate::rsa::RsaKeyPair; mod util; -pub use util::generate_random_bytes; +pub use util::{generate_random_alphanumeric, generate_random_bytes, pbkdf2}; mod wordlist; -pub use util::pbkdf2; pub use wordlist::EFF_LONG_WORD_LIST; mod allocator; pub use allocator::ZeroizingAllocator; diff --git a/crates/bitwarden-crypto/src/util.rs b/crates/bitwarden-crypto/src/util.rs index b78a4f5ec..72036c615 100644 --- a/crates/bitwarden-crypto/src/util.rs +++ b/crates/bitwarden-crypto/src/util.rs @@ -4,7 +4,7 @@ use ::aes::cipher::{ArrayLength, Unsigned}; use generic_array::GenericArray; use hmac::digest::OutputSizeUser; use rand::{ - distributions::{Distribution, Standard}, + distributions::{Alphanumeric, DistString, Distribution, Standard}, Rng, }; use zeroize::{Zeroize, Zeroizing}; @@ -39,6 +39,14 @@ where Zeroizing::new(rand::thread_rng().gen::()) } +/// Generate a random alphanumeric string of a given length +/// +/// Note: Do not use this generating user facing passwords. Use the `bitwarden-generator` crate for +/// that. +pub fn generate_random_alphanumeric(len: usize) -> String { + Alphanumeric.sample_string(&mut rand::thread_rng(), len) +} + pub fn pbkdf2(password: &[u8], salt: &[u8], rounds: u32) -> [u8; PBKDF_SHA256_HMAC_OUT_SIZE] { pbkdf2::pbkdf2_array::(password, salt, rounds) .expect("hash is a valid fixed size") diff --git a/crates/bitwarden/src/auth/auth_request.rs b/crates/bitwarden/src/auth/auth_request.rs index 7d90b6a36..1abe86ed9 100644 --- a/crates/bitwarden/src/auth/auth_request.rs +++ b/crates/bitwarden/src/auth/auth_request.rs @@ -1,11 +1,11 @@ use base64::{engine::general_purpose::STANDARD, Engine}; use bitwarden_core::VaultLocked; use bitwarden_crypto::{ - fingerprint, AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey, + fingerprint, generate_random_alphanumeric, AsymmetricCryptoKey, AsymmetricEncString, + AsymmetricPublicCryptoKey, }; #[cfg(feature = "internal")] use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; -use bitwarden_generators::{password, PasswordGeneratorRequest}; use crate::{error::Error, Client}; @@ -41,14 +41,7 @@ pub(crate) fn new_auth_request(email: &str) -> Result Date: Mon, 24 Jun 2024 13:13:21 -0400 Subject: [PATCH 03/11] [deps]: Update dtolnay/rust-toolchain digest to 21dc36f (#855) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/build-android.yml | 4 ++-- .github/workflows/build-cli.yml | 10 +++++----- .github/workflows/build-napi.yml | 2 +- .github/workflows/build-python-wheels.yml | 2 +- .github/workflows/build-rust-crates.yml | 4 ++-- .github/workflows/build-rust-cross-platform.yml | 2 +- .github/workflows/build-wasm.yml | 2 +- .github/workflows/direct-minimal-versions.yml | 2 +- .github/workflows/generate_schemas.yml | 2 +- .github/workflows/lint.yml | 2 +- .github/workflows/memory-testing.yml | 2 +- .github/workflows/minimum-rust-version.yml | 2 +- .github/workflows/publish-rust-crates.yml | 2 +- .github/workflows/release-cli.yml | 2 +- .github/workflows/rust-test.yml | 6 +++--- .github/workflows/version-bump.yml | 2 +- 16 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 58a12f7f0..3bd77bb75 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -28,7 +28,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable @@ -70,7 +70,7 @@ jobs: fetch-depth: 0 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 20e22632b..245b36b7c 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -61,7 +61,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} @@ -151,7 +151,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} @@ -266,7 +266,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} @@ -413,7 +413,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable @@ -448,7 +448,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/build-napi.yml b/.github/workflows/build-napi.yml index 87231d5f0..81fa07417 100644 --- a/.github/workflows/build-napi.yml +++ b/.github/workflows/build-napi.yml @@ -61,7 +61,7 @@ jobs: cache-dependency-path: crates/bitwarden-napi/package-lock.json - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} diff --git a/.github/workflows/build-python-wheels.yml b/.github/workflows/build-python-wheels.yml index bc718a430..766fcaf1e 100644 --- a/.github/workflows/build-python-wheels.yml +++ b/.github/workflows/build-python-wheels.yml @@ -71,7 +71,7 @@ jobs: node-version: 18 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} diff --git a/.github/workflows/build-rust-crates.yml b/.github/workflows/build-rust-crates.yml index 60a982814..3cbf16aa0 100644 --- a/.github/workflows/build-rust-crates.yml +++ b/.github/workflows/build-rust-crates.yml @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} @@ -69,7 +69,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: ${{ matrix.settings.target }} diff --git a/.github/workflows/build-rust-cross-platform.yml b/.github/workflows/build-rust-cross-platform.yml index ab56a47e8..0c99a5a23 100644 --- a/.github/workflows/build-rust-cross-platform.yml +++ b/.github/workflows/build-rust-cross-platform.yml @@ -38,7 +38,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/build-wasm.yml b/.github/workflows/build-wasm.yml index 760e83254..45313782f 100644 --- a/.github/workflows/build-wasm.yml +++ b/.github/workflows/build-wasm.yml @@ -35,7 +35,7 @@ jobs: run: npm i -g binaryen - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: wasm32-unknown-unknown diff --git a/.github/workflows/direct-minimal-versions.yml b/.github/workflows/direct-minimal-versions.yml index c9d3900ee..0c58466e1 100644 --- a/.github/workflows/direct-minimal-versions.yml +++ b/.github/workflows/direct-minimal-versions.yml @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: nightly targets: ${{ matrix.settings.target }} diff --git a/.github/workflows/generate_schemas.yml b/.github/workflows/generate_schemas.yml index 008ee31e9..cf21c54e8 100644 --- a/.github/workflows/generate_schemas.yml +++ b/.github/workflows/generate_schemas.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b9b6d4d73..3e5e2a1eb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/memory-testing.yml b/.github/workflows/memory-testing.yml index c0a9fbecd..8b577608f 100644 --- a/.github/workflows/memory-testing.yml +++ b/.github/workflows/memory-testing.yml @@ -30,7 +30,7 @@ jobs: sudo apt -y install gdb - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/minimum-rust-version.yml b/.github/workflows/minimum-rust-version.yml index af309ceed..f5dbdab4d 100644 --- a/.github/workflows/minimum-rust-version.yml +++ b/.github/workflows/minimum-rust-version.yml @@ -30,7 +30,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: # Important: When updating this, make sure to update the Readme file # and also the `rust-version` field in all the `Cargo.toml`. diff --git a/.github/workflows/publish-rust-crates.yml b/.github/workflows/publish-rust-crates.yml index deeef87cd..f4da56342 100644 --- a/.github/workflows/publish-rust-crates.yml +++ b/.github/workflows/publish-rust-crates.yml @@ -203,7 +203,7 @@ jobs: secrets: "cratesio-api-token" - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index df9715bb1..656f162c2 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -142,7 +142,7 @@ jobs: secrets: "cratesio-api-token" - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable diff --git a/.github/workflows/rust-test.yml b/.github/workflows/rust-test.yml index 8aa844293..9338a093d 100644 --- a/.github/workflows/rust-test.yml +++ b/.github/workflows/rust-test.yml @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable @@ -58,7 +58,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable components: llvm-tools @@ -87,7 +87,7 @@ jobs: uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable targets: wasm32-unknown-unknown diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 406f3b927..24a2c7997 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Install rust - uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a # stable + uses: dtolnay/rust-toolchain@21dc36fb71dd22e3317045c0c31a3f4249868b17 # stable with: toolchain: stable From ef86ab9a24db71e35e49fe1ca3e1eafde3eb1738 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 25 Jun 2024 11:02:30 +0200 Subject: [PATCH 04/11] Add login username to fido2 name fallback (#857) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 🎟ī¸ Tracking ## 📔 Objective Add `LoginView.username` to `user_name_for_ui` in `Fido2CredentialAutofillView` ## 📸 Screenshots ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## đŸĻŽ Reviewer guidelines - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹī¸ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or ⚠ī¸ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or â™ģī¸ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes --- crates/bitwarden-fido/src/types.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bitwarden-fido/src/types.rs b/crates/bitwarden-fido/src/types.rs index d6eaa4752..79777d24c 100644 --- a/crates/bitwarden-fido/src/types.rs +++ b/crates/bitwarden-fido/src/types.rs @@ -77,6 +77,10 @@ impl Fido2CredentialAutofillView { .user_name .none_whitespace() .or(c.user_display_name.none_whitespace()) + .or(cipher + .login + .as_ref() + .and_then(|l| l.username.none_whitespace())) .or(cipher.name.none_whitespace()), }) }) From 47cf3cc7708b759b9c137aff737f2542e285a76d Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Wed, 26 Jun 2024 17:18:44 +0200 Subject: [PATCH 05/11] [PM-8301] Invert crates relationship (#798) This PR inverts the relationship between most crates in an effort to make the code base easier to maintain. - Moves most of the logic into `bitwarden-core`. - `bitwarden` provides re-exports from the various crates. - Moved `ClientFeature` structs to the various crates, and introduced `ClientFeatureExt` which exposes it on `Client`. This now becomes the typical way to use functionality. - Created `InternalClient` which contains the internal functionality for hooking up logic between the various crates. --- Cargo.lock | 70 ++++-- Cargo.toml | 1 + .../CHANGELOG.md | 0 crates/bitwarden-core/Cargo.toml | 80 ++++++- crates/bitwarden-core/README.md | 2 +- .../src/.gitignore | 0 .../src/admin_console/mod.rs | 0 .../src/admin_console/policy.rs | 6 +- .../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 | 1 + .../src/auth/api/request/mod.rs | 17 +- .../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 | 9 +- .../src/auth/client_auth.rs | 40 ++-- .../src/auth/jwt_token.rs | 0 .../src/auth/login/access_token.rs | 48 ++-- .../src/auth/login/api_key.rs | 25 +- .../src/auth/login/auth_request.rs | 21 +- .../src/auth/login/mod.rs | 8 +- .../src/auth/login/password.rs | 27 ++- .../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 | 2 +- .../src/auth/mod.rs | 18 +- .../src/auth/password/mod.rs | 0 .../src/auth/password/policy.rs | 0 .../src/auth/password/strength.rs | 0 .../src/auth/password/validate.rs | 73 ++++-- .../src/auth/register.rs | 6 +- .../src/auth/renew.rs | 17 +- .../src/auth/tde.rs | 20 +- crates/bitwarden-core/src/client/client.rs | 105 ++++++++ .../src/client/client_settings.rs | 2 +- .../src/client/encryption_settings.rs | 6 +- .../src/client/flags.rs | 0 .../src/client/internal.rs} | 224 +++++------------- .../bitwarden-core/src/client/login_method.rs | 46 ++++ crates/bitwarden-core/src/client/mod.rs | 20 ++ .../src/client/test_accounts.rs | 3 +- crates/bitwarden-core/src/error.rs | 116 +++++++++ crates/bitwarden-core/src/lib.rs | 15 ++ .../src/mobile/client_crypto.rs | 0 .../src/mobile/client_kdf.rs | 4 +- .../src/mobile/crypto.rs | 88 ++++--- .../src/mobile/kdf.rs | 0 .../src/mobile/mod.rs | 2 - .../src/platform/client_platform.rs | 9 - .../src/platform/generate_fingerprint.rs | 7 +- .../src/platform/get_user_api_key.rs | 12 +- .../src/platform/mod.rs | 9 - .../platform/secret_verification_request.rs | 0 .../bitwarden-core/src/secrets_manager/mod.rs | 1 + .../src/secrets_manager/state.rs | 0 crates/bitwarden-core/src/uniffi_support.rs | 11 + .../{bitwarden => bitwarden-core}/src/util.rs | 0 .../tests/register.rs | 2 +- crates/bitwarden-crypto/Cargo.toml | 2 +- crates/bitwarden-exporters/Cargo.toml | 7 +- .../src}/client_exporter.rs | 27 ++- crates/bitwarden-exporters/src/error.rs | 21 ++ crates/bitwarden-exporters/src/export.rs | 43 ++++ crates/bitwarden-exporters/src/lib.rs | 48 ++-- .../uniffi.toml | 6 +- crates/bitwarden-fido/Cargo.toml | 4 +- crates/bitwarden-fido/src/authenticator.rs | 38 +-- .../src}/client_fido.rs | 36 +-- crates/bitwarden-fido/src/lib.rs | 6 +- crates/bitwarden-generators/Cargo.toml | 1 + .../src}/client_generator.rs | 53 +++-- crates/bitwarden-generators/src/lib.rs | 2 + crates/bitwarden-json/src/client.rs | 4 + crates/bitwarden-send/Cargo.toml | 2 +- .../src}/client_sends.rs | 48 ++-- crates/bitwarden-send/src/lib.rs | 2 + crates/bitwarden-send/src/send.rs | 2 +- crates/bitwarden-sm/Cargo.toml | 32 +++ crates/bitwarden-sm/src/client_projects.rs | 50 ++++ crates/bitwarden-sm/src/client_secrets.rs | 70 ++++++ crates/bitwarden-sm/src/lib.rs | 7 + .../src}/projects/create.rs | 9 +- .../src}/projects/delete.rs | 12 +- .../src}/projects/get.rs | 8 +- .../src}/projects/list.rs | 16 +- .../src}/projects/mod.rs | 0 .../src}/projects/project_response.rs | 6 +- .../src}/projects/update.rs | 9 +- .../src}/secrets/create.rs | 9 +- .../src}/secrets/delete.rs | 12 +- .../src}/secrets/get.rs | 8 +- .../src}/secrets/get_by_ids.rs | 8 +- .../src}/secrets/list.rs | 26 +- .../src}/secrets/mod.rs | 0 .../src}/secrets/secret_response.rs | 10 +- .../src}/secrets/sync.rs | 11 +- .../src}/secrets/update.rs | 10 +- crates/bitwarden-uniffi/Cargo.toml | 1 + crates/bitwarden-uniffi/src/docs.rs | 3 +- crates/bitwarden-uniffi/src/error.rs | 6 + crates/bitwarden-uniffi/src/platform/fido2.rs | 46 ++-- crates/bitwarden-uniffi/src/platform/mod.rs | 2 +- crates/bitwarden-uniffi/src/tool/mod.rs | 36 ++- crates/bitwarden-uniffi/src/tool/sends.rs | 2 +- .../bitwarden-uniffi/src/vault/attachments.rs | 4 +- crates/bitwarden-uniffi/src/vault/ciphers.rs | 8 +- .../bitwarden-uniffi/src/vault/collections.rs | 2 +- crates/bitwarden-uniffi/src/vault/folders.rs | 2 +- crates/bitwarden-uniffi/src/vault/mod.rs | 12 +- .../src/vault/password_history.rs | 2 +- crates/bitwarden-vault/Cargo.toml | 7 +- crates/bitwarden-vault/src/cipher/cipher.rs | 15 +- .../src}/client_totp.rs | 7 +- crates/bitwarden-vault/src/client_vault.rs | 30 +++ crates/bitwarden-vault/src/lib.rs | 6 + .../src/mobile}/client_attachments.rs | 22 +- .../src/mobile}/client_ciphers.rs | 45 ++-- .../src/mobile}/client_collection.rs | 21 +- .../src/mobile}/client_folders.rs | 16 +- .../src/mobile}/client_password_history.rs | 15 +- crates/bitwarden-vault/src/mobile/mod.rs | 5 + .../src/vault => bitwarden-vault/src}/sync.rs | 55 +++-- crates/bitwarden-wasm/Cargo.toml | 8 + crates/bitwarden-wasm/build.sh | 4 +- crates/bitwarden/Cargo.toml | 62 +---- crates/bitwarden/README.md | 6 +- crates/bitwarden/src/client/mod.rs | 17 -- crates/bitwarden/src/error.rs | 97 +------- crates/bitwarden/src/lib.rs | 59 ++--- crates/bitwarden/src/mobile/tool/mod.rs | 2 - crates/bitwarden/src/mobile/vault/mod.rs | 12 - .../src/secrets_manager/client_projects.rs | 41 ---- .../src/secrets_manager/client_secrets.rs | 62 ----- crates/bitwarden/src/secrets_manager/mod.rs | 9 - crates/bitwarden/src/tool/exporters/mod.rs | 115 --------- crates/bitwarden/src/tool/mod.rs | 5 - crates/bitwarden/src/uniffi_support.rs | 16 -- crates/bitwarden/src/vault/client_vault.rs | 18 -- crates/bitwarden/src/vault/mod.rs | 9 - crates/bw/src/auth/login.rs | 2 +- crates/bw/src/main.rs | 2 +- crates/bws/src/command/project.rs | 9 +- crates/bws/src/command/secret.rs | 9 +- crates/bws/src/main.rs | 2 +- .../bitwarden/myapplication/MainActivity.kt | 6 +- 172 files changed, 1542 insertions(+), 1238 deletions(-) rename crates/{bitwarden => bitwarden-core}/CHANGELOG.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 (98%) 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 (98%) rename crates/{bitwarden => bitwarden-core}/src/auth/api/request/mod.rs (92%) 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 (98%) rename crates/{bitwarden => bitwarden-core}/src/auth/client_auth.rs (91%) rename crates/{bitwarden => bitwarden-core}/src/auth/jwt_token.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/access_token.rs (85%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/api_key.rs (84%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/auth_request.rs (88%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/mod.rs (91%) rename crates/{bitwarden => bitwarden-core}/src/auth/login/password.rs (88%) 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 (96%) rename crates/{bitwarden => bitwarden-core}/src/auth/mod.rs (95%) 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 (83%) rename crates/{bitwarden => bitwarden-core}/src/auth/register.rs (92%) rename crates/{bitwarden => bitwarden-core}/src/auth/renew.rs (89%) rename crates/{bitwarden => bitwarden-core}/src/auth/tde.rs (80%) create mode 100644 crates/bitwarden-core/src/client/client.rs rename crates/{bitwarden => bitwarden-core}/src/client/client_settings.rs (97%) rename crates/{bitwarden => bitwarden-core}/src/client/encryption_settings.rs (96%) rename crates/{bitwarden => bitwarden-core}/src/client/flags.rs (100%) rename crates/{bitwarden/src/client/client.rs => bitwarden-core/src/client/internal.rs} (57%) create mode 100644 crates/bitwarden-core/src/client/login_method.rs create mode 100644 crates/bitwarden-core/src/client/mod.rs rename crates/{bitwarden => bitwarden-core}/src/client/test_accounts.rs (99%) rename crates/{bitwarden => bitwarden-core}/src/mobile/client_crypto.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/client_kdf.rs (80%) rename crates/{bitwarden => bitwarden-core}/src/mobile/crypto.rs (90%) rename crates/{bitwarden => bitwarden-core}/src/mobile/kdf.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/mobile/mod.rs (82%) rename crates/{bitwarden => bitwarden-core}/src/platform/client_platform.rs (81%) rename crates/{bitwarden => bitwarden-core}/src/platform/generate_fingerprint.rs (96%) rename crates/{bitwarden => bitwarden-core}/src/platform/get_user_api_key.rs (90%) rename crates/{bitwarden => bitwarden-core}/src/platform/mod.rs (63%) rename crates/{bitwarden => bitwarden-core}/src/platform/secret_verification_request.rs (100%) create mode 100644 crates/bitwarden-core/src/secrets_manager/mod.rs rename crates/{bitwarden => bitwarden-core}/src/secrets_manager/state.rs (100%) rename crates/{bitwarden => bitwarden-core}/src/util.rs (100%) rename crates/{bitwarden => bitwarden-core}/tests/register.rs (97%) rename crates/{bitwarden/src/tool/exporters => bitwarden-exporters/src}/client_exporter.rs (52%) create mode 100644 crates/bitwarden-exporters/src/error.rs create mode 100644 crates/bitwarden-exporters/src/export.rs rename crates/{bitwarden => bitwarden-exporters}/uniffi.toml (50%) rename crates/{bitwarden/src/platform => bitwarden-fido/src}/client_fido.rs (71%) rename crates/{bitwarden/src/tool => bitwarden-generators/src}/client_generator.rs (63%) rename crates/{bitwarden/src/mobile/tool => bitwarden-send/src}/client_sends.rs (65%) 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/src/secrets_manager => bitwarden-sm/src}/projects/create.rs (82%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/delete.rs (86%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/get.rs (72%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/list.rs (85%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/mod.rs (100%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/project_response.rs (90%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/projects/update.rs (82%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/create.rs (86%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/delete.rs (86%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/get.rs (73%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/get_by_ids.rs (77%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/list.rs (85%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/mod.rs (100%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/secret_response.rs (93%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/sync.rs (86%) rename crates/{bitwarden/src/secrets_manager => bitwarden-sm/src}/secrets/update.rs (85%) rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src}/client_totp.rs (66%) create mode 100644 crates/bitwarden-vault/src/client_vault.rs rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src/mobile}/client_attachments.rs (83%) rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src/mobile}/client_ciphers.rs (89%) rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src/mobile}/client_collection.rs (81%) rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src/mobile}/client_folders.rs (69%) rename crates/{bitwarden/src/mobile/vault => bitwarden-vault/src/mobile}/client_password_history.rs (65%) create mode 100644 crates/bitwarden-vault/src/mobile/mod.rs rename crates/{bitwarden/src/vault => bitwarden-vault/src}/sync.rs (76%) delete mode 100644 crates/bitwarden/src/client/mod.rs delete mode 100644 crates/bitwarden/src/mobile/tool/mod.rs delete mode 100644 crates/bitwarden/src/mobile/vault/mod.rs delete mode 100644 crates/bitwarden/src/secrets_manager/client_projects.rs delete mode 100644 crates/bitwarden/src/secrets_manager/client_secrets.rs delete mode 100644 crates/bitwarden/src/secrets_manager/mod.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/uniffi_support.rs delete mode 100644 crates/bitwarden/src/vault/client_vault.rs delete mode 100644 crates/bitwarden/src/vault/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e4c3f54c0..a1c0dbe4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,8 +357,6 @@ checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" name = "bitwarden" version = "0.5.0" dependencies = [ - "async-trait", - "base64 0.22.1", "bitwarden-api-api", "bitwarden-api-identity", "bitwarden-core", @@ -367,27 +365,10 @@ 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 +420,37 @@ dependencies = [ name = "bitwarden-core" version = "0.5.0" dependencies = [ + "async-trait", + "base64 0.22.1", + "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 +494,11 @@ dependencies = [ "bitwarden-vault", "chrono", "csv", + "schemars", "serde", "serde_json", "thiserror", + "uniffi", "uuid", ] @@ -520,6 +530,7 @@ dependencies = [ name = "bitwarden-generators" version = "0.5.0" dependencies = [ + "bitwarden-core", "bitwarden-crypto", "rand", "rand_chacha", @@ -586,6 +597,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "bitwarden-sm" +version = "0.5.0" +dependencies = [ + "bitwarden-api-api", + "bitwarden-core", + "bitwarden-crypto", + "chrono", + "schemars", + "serde", + "serde_json", + "thiserror", + "uniffi", + "uuid", +] + [[package]] name = "bitwarden-uniffi" version = "0.1.0" @@ -595,6 +622,7 @@ dependencies = [ "bitwarden", "bitwarden-core", "bitwarden-crypto", + "bitwarden-exporters", "bitwarden-fido", "bitwarden-generators", "bitwarden-send", @@ -627,6 +655,7 @@ dependencies = [ "sha1", "sha2", "thiserror", + "tokio", "uniffi", "uuid", ] @@ -637,6 +666,7 @@ version = "0.1.0" dependencies = [ "argon2", "bitwarden-json", + "chrono", "console_error_panic_hook", "console_log", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 121c7733f..e721d9090 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ bitwarden-exporters = { path = "crates/bitwarden-exporters", version = "=0.5.0" bitwarden-fido = { path = "crates/bitwarden-fido", 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" } bitwarden-vault = { path = "crates/bitwarden-vault", version = "=0.5.0" } [workspace.lints.clippy] 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-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index 5f755020c..ba3ebbe68 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -3,6 +3,7 @@ name = "bitwarden-core" description = """ Internal crate for the bitwarden crate. Do not use. """ +keywords = ["bitwarden"] version.workspace = true authors.workspace = true @@ -11,16 +12,85 @@ rust-version.workspace = true homepage.workspace = true repository.workspace = true license-file.workspace = true -keywords.workspace = true [features] -uniffi = ["dep:uniffi"] +internal = [] # Internal testing methods +no-memory-hardening = [ + "bitwarden-crypto/no-memory-hardening", +] # Disable memory hardening features +uniffi = [ + "bitwarden-crypto/uniffi", + "dep:uniffi", + "dep:passkey", + "dep:coset", + "dep:p256", +] # Uniffi bindings +secrets = [] # Secrets manager API [dependencies] -chrono = { version = ">=0.4.26, <0.5", default-features = false } -uniffi = { version = "=0.27.2", optional = true } -uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } +async-trait = ">=0.1.80, <0.2" +base64 = ">=0.22.1, <0.23" +bitwarden-api-api = { workspace = true } +bitwarden-api-identity = { workspace = true } +bitwarden-crypto = { workspace = true } +chrono = { version = ">=0.4.26, <0.5", features = [ + "clock", + "serde", + "std", +], default-features = false } +coset = { version = "0.3.7", optional = true } +# We don't use this directly (it's used by rand), but we need it here to enable WASM support +getrandom = { version = ">=0.2.9, <0.3", features = ["js"] } +hmac = ">=0.12.1, <0.13" +log = ">=0.4.18, <0.5" +p256 = { version = ">=0.13.2, <0.14", optional = true } +passkey = { git = "https://github.com/bitwarden/passkey-rs", rev = "c48c2ddfd6b884b2d754432576c66cb2b1985a3a", optional = true } +rand = ">=0.8.5, <0.9" +reqwest = { version = ">=0.12.5, <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" +serde_qs = ">=0.12.0, <0.14" +serde_repr = ">=0.1.12, <0.2" +sha1 = ">=0.10.5, <0.11" +sha2 = ">=0.10.6, <0.11" thiserror = ">=1.0.40, <2.0" +uniffi = { version = "=0.27.2", optional = true, features = ["tokio"] } +uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } +zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } +zxcvbn = ">= 2.2.2, <3.0" + +[target.'cfg(all(not(target_os = "android"), not(target_arch="wasm32")))'.dependencies] +# By default, we use rustls as the TLS stack and rust-platform-verifier to support user-installed root certificates +# There are a few exceptions to this: +# - WASM doesn't require a TLS stack, as it just uses the browsers/node fetch +# - Android uses webpki-roots for the moment +reqwest = { version = ">=0.12.5, <0.13", features = [ + "rustls-tls-manual-roots", +], default-features = false } +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 +# This means that for the moment android won't support self-signed certificates, even if they are included in the OS trust store +reqwest = { version = ">=0.12.5, <0.13", features = [ + "rustls-tls-webpki-roots", +], default-features = false } + +# This is a workaround to fix a bug with version 2.11.0 that added some symbols that are not available on iOS +# The bug is fixed already but the fix is not released yet. https://github.com/kornelski/rust-security-framework/pull/204 +[target.'cfg(target_os = "ios")'.dependencies] +security-framework = { version = "=2.10" } + +[dev-dependencies] +bitwarden-crypto = { workspace = true } +rand_chacha = "0.3.1" +tokio = { version = "1.36.0", features = ["rt", "macros"] } +wiremock = "0.6.0" +zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } [lints] workspace = true diff --git a/crates/bitwarden-core/README.md b/crates/bitwarden-core/README.md index fd697aa3c..baddb938e 100644 --- a/crates/bitwarden-core/README.md +++ b/crates/bitwarden-core/README.md @@ -1,4 +1,4 @@ -# Bitwarden Crypto +# Bitwarden Core 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. 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 98% rename from crates/bitwarden/src/admin_console/policy.rs rename to crates/bitwarden-core/src/admin_console/policy.rs index 6c0a2ec65..cde09c24c 100644 --- a/crates/bitwarden/src/admin_console/policy.rs +++ b/crates/bitwarden-core/src/admin_console/policy.rs @@ -1,13 +1,15 @@ use std::collections::HashMap; use bitwarden_api_api::models::PolicyResponseModel; -use bitwarden_core::require; 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/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 98% 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 index 17ef52c26..2b2a47839 100644 --- 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 @@ -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/src/auth/api/request/mod.rs b/crates/bitwarden-core/src/auth/api/request/mod.rs similarity index 92% rename from crates/bitwarden/src/auth/api/request/mod.rs rename to crates/bitwarden-core/src/auth/api/request/mod.rs index c0cb45251..0d9f39877 100644 --- a/crates/bitwarden/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/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 98% rename from crates/bitwarden/src/auth/auth_request.rs rename to crates/bitwarden-core/src/auth/auth_request.rs index 1abe86ed9..7d59f6e69 100644 --- a/crates/bitwarden/src/auth/auth_request.rs +++ b/crates/bitwarden-core/src/auth/auth_request.rs @@ -1,5 +1,4 @@ use base64::{engine::general_purpose::STANDARD, Engine}; -use bitwarden_core::VaultLocked; use bitwarden_crypto::{ fingerprint, generate_random_alphanumeric, AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey, @@ -7,7 +6,7 @@ use bitwarden_crypto::{ #[cfg(feature = "internal")] use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; -use crate::{error::Error, Client}; +use crate::{error::Error, Client, VaultLocked}; #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] pub struct AuthRequestResponse { @@ -82,7 +81,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(VaultLocked)?; Ok(AsymmetricEncString::encrypt_rsa2048_oaep_sha1( @@ -137,6 +136,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(); @@ -205,6 +205,7 @@ mod tests { .unwrap(); existing_device + .internal .initialize_user_crypto_master_key(master_key, user_key, private_key.parse().unwrap()) .unwrap(); @@ -236,12 +237,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/src/auth/client_auth.rs b/crates/bitwarden-core/src/auth/client_auth.rs similarity index 91% rename from crates/bitwarden/src/auth/client_auth.rs rename to crates/bitwarden-core/src/auth/client_auth.rs index 2ea92decc..fa48481e6 100644 --- a/crates/bitwarden/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, @@ -32,7 +28,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")] @@ -154,9 +150,9 @@ impl<'a> ClientAuth<'a> { #[cfg(feature = "internal")] fn trust_device(client: &Client) -> Result { - use bitwarden_core::VaultLocked; + use crate::VaultLocked; - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let user_key = enc.get_key(&None).ok_or(VaultLocked)?; @@ -169,6 +165,7 @@ impl<'a> Client { } } +/* #[cfg(test)] mod tests { @@ -267,3 +264,4 @@ mod tests { assert_eq!(res.value, "TEST"); } } + */ 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 85% rename from crates/bitwarden/src/auth/login/access_token.rs rename to crates/bitwarden-core/src/auth/login/access_token.rs index 25d8ffb5d..c445e43c7 100644 --- a/crates/bitwarden/src/auth/login/access_token.rs +++ b/crates/bitwarden-core/src/auth/login/access_token.rs @@ -1,7 +1,6 @@ use std::path::{Path, PathBuf}; use base64::{engine::general_purpose::STANDARD, Engine}; -use bitwarden_core::require; use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey}; use chrono::Utc; use schemars::JsonSchema; @@ -16,6 +15,7 @@ use crate::{ }, client::{LoginMethod, ServiceAccountLoginMethod}, error::{Error, Result}, + require, secrets_manager::state::{self, ClientState}, Client, }; @@ -31,13 +31,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, @@ -79,20 +81,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) @@ -102,7 +106,7 @@ async fn request_access_token( client: &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 @@ -126,8 +130,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/src/auth/login/api_key.rs b/crates/bitwarden-core/src/auth/login/api_key.rs similarity index 84% rename from crates/bitwarden/src/auth/login/api_key.rs rename to crates/bitwarden-core/src/auth/login/api_key.rs index 92f1c76b9..b0e2c8834 100644 --- a/crates/bitwarden/src/auth/login/api_key.rs +++ b/crates/bitwarden-core/src/auth/login/api_key.rs @@ -1,4 +1,3 @@ -use bitwarden_core::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( @@ -33,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, @@ -41,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) @@ -61,7 +64,7 @@ async fn request_api_identity_tokens( client: &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/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs similarity index 88% rename from crates/bitwarden/src/auth/login/auth_request.rs rename to crates/bitwarden-core/src/auth/login/auth_request.rs index 380a49b9d..912105db0 100644 --- a/crates/bitwarden/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -2,7 +2,6 @@ use bitwarden_api_api::{ apis::auth_requests_api::{auth_requests_id_response_get, auth_requests_post}, models::{AuthRequestCreateRequestModel, AuthRequestType}, }; -use bitwarden_core::require; use bitwarden_crypto::Kdf; use uuid::Uuid; @@ -14,7 +13,7 @@ use crate::{ client::{LoginMethod, UserLoginMethod}, error::Result, mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, - Client, + require, Client, }; pub struct NewAuthRequestResponse { @@ -31,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)?; @@ -59,7 +58,7 @@ pub(crate) async fn complete_auth_request( client: &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, @@ -87,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/src/auth/login/mod.rs b/crates/bitwarden-core/src/auth/login/mod.rs similarity index 91% rename from crates/bitwarden/src/auth/login/mod.rs rename to crates/bitwarden-core/src/auth/login/mod.rs index 9c9c711b9..0c90dc973 100644 --- a/crates/bitwarden/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; @@ -49,7 +53,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/src/auth/login/password.rs b/crates/bitwarden-core/src/auth/login/password.rs similarity index 88% rename from crates/bitwarden/src/auth/login/password.rs rename to crates/bitwarden-core/src/auth/login/password.rs index 8d79d8568..4536657d3 100644 --- a/crates/bitwarden/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::{ @@ -22,10 +24,9 @@ pub(crate) async fn login_password( client: &Client, input: &PasswordLoginRequest, ) -> Result { - use bitwarden_core::require; use bitwarden_crypto::{EncString, HashPurpose, MasterKey}; - use crate::client::UserLoginMethod; + use crate::{client::UserLoginMethod, require}; info!("password logging in"); @@ -40,21 +41,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) @@ -68,7 +73,7 @@ async fn request_identity_tokens( ) -> Result { use crate::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/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 96% rename from crates/bitwarden/src/auth/login/two_factor.rs rename to crates/bitwarden-core/src/auth/login/two_factor.rs index 197ff77a1..c0a4c10ab 100644 --- a/crates/bitwarden/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/src/auth/mod.rs b/crates/bitwarden-core/src/auth/mod.rs similarity index 95% rename from crates/bitwarden/src/auth/mod.rs rename to crates/bitwarden-core/src/auth/mod.rs index ee409ddd6..b092ba98a 100644 --- a/crates/bitwarden/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; -#[cfg(feature = "internal")] -use bitwarden_crypto::{HashPurpose, MasterKey}; -#[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")] pub(crate) use auth_request::{auth_request_decrypt_master_key, auth_request_decrypt_user_key}; + +#[cfg(feature = "internal")] +mod register; +#[cfg(feature = "internal")] +pub use register::{RegisterKeyResponse, RegisterRequest}; + #[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/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 83% rename from crates/bitwarden/src/auth/password/validate.rs rename to crates/bitwarden-core/src/auth/password/validate.rs index 2a077418a..ebb5395d1 100644 --- a/crates/bitwarden/src/auth/password/validate.rs +++ b/crates/bitwarden-core/src/auth/password/validate.rs @@ -13,8 +13,12 @@ pub(crate) fn validate_password( password: String, password_hash: String, ) -> Result { - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; + let login_method = client + .internal + .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, .. } @@ -40,10 +44,14 @@ pub(crate) fn validate_password_user_key( password: String, encrypted_user_key: String, ) -> Result { - use bitwarden_core::VaultLocked; + use crate::VaultLocked; - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; + let login_method = client + .internal + .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, .. } @@ -53,7 +61,10 @@ pub(crate) fn validate_password_user_key( .decrypt_user_key(encrypted_user_key.parse()?) .map_err(|_| "wrong password")?; - let enc = client.get_encryption_settings().map_err(|_| VaultLocked)?; + let enc = client + .internal + .get_encryption_settings() + .map_err(|_| VaultLocked)?; let existing_key = enc.get_key(&None).ok_or(VaultLocked)?; @@ -72,22 +83,26 @@ 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.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(); @@ -102,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); @@ -112,11 +129,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) @@ -126,6 +145,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(); @@ -142,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); @@ -152,11 +174,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(); @@ -165,6 +189,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/src/auth/register.rs b/crates/bitwarden-core/src/auth/register.rs similarity index 92% rename from crates/bitwarden/src/auth/register.rs rename to crates/bitwarden-core/src/auth/register.rs index 5ca995ead..07e5e87ba 100644 --- a/crates/bitwarden/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)] @@ -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.get_api_configurations().await; + let config = client.internal.get_api_configurations().await; let kdf = Kdf::default(); diff --git a/crates/bitwarden/src/auth/renew.rs b/crates/bitwarden-core/src/auth/renew.rs similarity index 89% rename from crates/bitwarden/src/auth/renew.rs rename to crates/bitwarden-core/src/auth/renew.rs index 01108cf2c..d53534d58 100644 --- a/crates/bitwarden/src/auth/renew.rs +++ b/crates/bitwarden-core/src/auth/renew.rs @@ -1,15 +1,18 @@ 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::{Client, 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: &Client) -> Result<()> { +pub(crate) async fn renew_token(client: &InternalClient) -> Result<()> { const TOKEN_RENEW_MARGIN_SECONDS: i64 = 5 * 60; let tokens = client @@ -35,7 +38,6 @@ pub(crate) async fn renew_token(client: &Client) -> 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: &Client) -> Result<()> { .await? } }, + #[cfg(feature = "secrets")] LoginMethod::ServiceAccount(s) => match s { ServiceAccountLoginMethod::AccessToken { access_token, diff --git a/crates/bitwarden/src/auth/tde.rs b/crates/bitwarden-core/src/auth/tde.rs similarity index 80% rename from crates/bitwarden/src/auth/tde.rs rename to crates/bitwarden-core/src/auth/tde.rs index e1ddb0921..8d99b50fe 100644 --- a/crates/bitwarden/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 new file mode 100644 index 000000000..3ea4ae7e8 --- /dev/null +++ b/crates/bitwarden-core/src/client/client.rs @@ -0,0 +1,105 @@ +use std::sync::{Arc, RwLock}; + +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, Tokens}, +}; + +/// The main struct to interact with the Bitwarden SDK. +#[derive(Debug)] +pub struct Client { + #[doc(hidden)] + pub internal: InternalClient, +} + +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 { + internal: InternalClient { + 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(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(); + } +} diff --git a/crates/bitwarden/src/client/client_settings.rs b/crates/bitwarden-core/src/client/client_settings.rs similarity index 97% rename from crates/bitwarden/src/client/client_settings.rs rename to crates/bitwarden-core/src/client/client_settings.rs index d82e5d93c..bd678d131 100644 --- a/crates/bitwarden/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/src/client/encryption_settings.rs b/crates/bitwarden-core/src/client/encryption_settings.rs similarity index 96% rename from crates/bitwarden/src/client/encryption_settings.rs rename to crates/bitwarden-core/src/client/encryption_settings.rs index f92dd5f09..138d1568e 100644 --- a/crates/bitwarden/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, @@ -72,9 +73,10 @@ impl EncryptionSettings { &mut self, org_enc_keys: Vec<(Uuid, AsymmetricEncString)>, ) -> Result<&Self> { - use bitwarden_core::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 @@ -93,7 +95,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/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/client.rs b/crates/bitwarden-core/src/client/internal.rs similarity index 57% rename from crates/bitwarden/src/client/client.rs rename to crates/bitwarden-core/src/client/internal.rs index 413e704aa..55122b9a1 100644 --- a/crates/bitwarden/src/client/client.rs +++ b/crates/bitwarden-core/src/client/internal.rs @@ -1,67 +1,32 @@ -use std::{ - path::PathBuf, - sync::{Arc, RwLock}, -}; +use std::sync::{Arc, RwLock}; -use bitwarden_core::VaultLocked; -#[cfg(feature = "internal")] -pub use bitwarden_crypto::Kdf; +#[cfg(any(feature = "internal", feature = "secrets"))] use bitwarden_crypto::SymmetricCryptoKey; #[cfg(feature = "internal")] -use bitwarden_crypto::{AsymmetricEncString, EncString, MasterKey}; +use bitwarden_crypto::{AsymmetricEncString, EncString, Kdf, MasterKey}; use chrono::Utc; -use reqwest::header::{self, HeaderValue}; use uuid::Uuid; +#[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::client::flags::Flags; +use crate::error::Error; use crate::{ - auth::AccessToken, client::encryption_settings::EncryptionSettings, error::Result, - ClientSettings, DeviceType, + auth::renew::renew_token, + error::{Result, VaultLocked}, + DeviceType, }; #[derive(Debug, Clone)] -pub(crate) struct ApiConfigurations { +pub 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 @@ -74,16 +39,15 @@ pub(crate) struct Tokens { pub(crate) refresh_token: Option, } -/// The main struct to interact with the Bitwarden SDK. #[derive(Debug)] -pub struct Client { +pub struct InternalClient { pub(crate) tokens: RwLock, pub(crate) login_method: RwLock>>, #[cfg(feature = "internal")] - flags: RwLock, + 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>, @@ -92,98 +56,20 @@ pub struct Client { #[allow(unused)] pub(crate) external_client: reqwest::Client, - encryption_settings: RwLock>>, + pub(super) 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), - } - } - +impl InternalClient { #[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 { + pub 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 @@ -199,6 +85,7 @@ impl Client { .expect("RwLock is not poisoned") .as_deref() { + #[cfg(feature = "secrets")] Some(LoginMethod::ServiceAccount(ServiceAccountLoginMethod::AccessToken { organization_id, .. @@ -207,14 +94,7 @@ impl Client { } } - pub(crate) fn get_encryption_settings(&self) -> Result, VaultLocked> { - self.encryption_settings - .read() - .expect("RwLock is not poisoned") - .clone() - .ok_or(VaultLocked) - } - + #[cfg(any(feature = "internal", feature = "secrets"))] pub(crate) fn set_login_method(&self, login_method: LoginMethod) { use log::debug; @@ -240,6 +120,7 @@ impl Client { *guard = Arc::new(inner); } + #[cfg(feature = "internal")] pub fn is_authed(&self) -> bool { let is_token_set = self .tokens @@ -256,6 +137,44 @@ impl Client { is_token_set || is_login_method_set } + #[cfg(feature = "internal")] + pub fn get_kdf(&self) -> Result { + match self + .login_method + .read() + .expect("RwLock is not poisoned") + .as_deref() + { + Some(LoginMethod::User( + UserLoginMethod::Username { kdf, .. } | UserLoginMethod::ApiKey { kdf, .. }, + )) => Ok(kdf.clone()), + _ => Err(Error::NotAuthenticated), + } + } + + 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. + renew_token(self).await.ok(); + self.__api_configurations + .read() + .expect("RwLock is not poisoned") + .clone() + } + + #[cfg(feature = "internal")] + pub fn get_http_client(&self) -> &reqwest::Client { + &self.external_client + } + + pub fn get_encryption_settings(&self) -> Result, VaultLocked> { + self.encryption_settings + .read() + .expect("RwLock is not poisoned") + .clone() + .ok_or(VaultLocked) + } + #[cfg(feature = "internal")] pub(crate) fn initialize_user_crypto_master_key( &self, @@ -302,6 +221,7 @@ impl Client { 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 @@ -311,7 +231,7 @@ impl Client { } #[cfg(feature = "internal")] - pub(crate) fn initialize_org_crypto( + pub fn initialize_org_crypto( &self, org_keys: Vec<(Uuid, AsymmetricEncString)>, ) -> Result> { @@ -333,23 +253,3 @@ impl Client { 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(); - } -} 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..67db15a71 --- /dev/null +++ b/crates/bitwarden-core/src/client/login_method.rs @@ -0,0 +1,46 @@ +#[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 { + #[allow(dead_code)] + User(UserLoginMethod), + // TODO: Organizations supports api key + // Organization(OrganizationLoginMethod), + #[cfg(feature = "secrets")] + ServiceAccount(ServiceAccountLoginMethod), +} + +#[allow(dead_code)] +#[derive(Debug)] +pub(crate) enum UserLoginMethod { + Username { + client_id: String, + email: String, + kdf: Kdf, + }, + ApiKey { + client_id: String, + client_secret: String, + + email: String, + kdf: Kdf, + }, +} + +#[cfg(feature = "secrets")] +#[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 new file mode 100644 index 000000000..1ef7d9357 --- /dev/null +++ b/crates/bitwarden-core/src/client/mod.rs @@ -0,0 +1,20 @@ +//! Bitwarden SDK Client + +#[allow(clippy::module_inception)] +mod client; +pub mod client_settings; +pub mod encryption_settings; +pub mod internal; +pub use internal::ApiConfigurations; +pub mod login_method; +#[cfg(feature = "secrets")] +pub(crate) use login_method::ServiceAccountLoginMethod; +pub(crate) use login_method::{LoginMethod, UserLoginMethod}; +#[cfg(feature = "internal")] +mod flags; + +pub use client::Client; +pub use client_settings::{ClientSettings, DeviceType}; + +#[cfg(feature = "internal")] +pub mod test_accounts; diff --git a/crates/bitwarden/src/client/test_accounts.rs b/crates/bitwarden-core/src/client/test_accounts.rs similarity index 99% rename from crates/bitwarden/src/client/test_accounts.rs rename to crates/bitwarden-core/src/client/test_accounts.rs index 7c24df0ac..4e83f2c14 100644 --- a/crates/bitwarden/src/client/test_accounts.rs +++ b/crates/bitwarden-core/src/client/test_accounts.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unwrap_used)] use std::collections::HashMap; use bitwarden_crypto::Kdf; @@ -14,7 +15,7 @@ impl Client { pub async fn init_test_account(account: TestAccount) -> Self { let client = Client::new(None); - client.load_flags(HashMap::from([( + client.internal.load_flags(HashMap::from([( "enableCipherKeyEncryption".to_owned(), true, )])); diff --git a/crates/bitwarden-core/src/error.rs b/crates/bitwarden-core/src/error.rs index 2c46407cc..e4ca94a25 100644 --- a/crates/bitwarden-core/src/error.rs +++ b/crates/bitwarden-core/src/error.rs @@ -1,5 +1,121 @@ +//! Errors that can occur when using this SDK + +use std::{borrow::Cow, fmt::Debug}; + +use bitwarden_api_api::apis::Error as ApiError; +use bitwarden_api_identity::apis::Error as IdentityError; +use reqwest::StatusCode; use thiserror::Error; +#[derive(Debug, Error)] +pub enum Error { + #[error(transparent)] + MissingFieldError(#[from] MissingFieldError), + #[error(transparent)] + VaultLocked(#[from] VaultLocked), + + #[error("The client is not authenticated or the session has expired")] + NotAuthenticated, + + #[error("Access token is not in a valid format: {0}")] + AccessTokenInvalid(#[from] AccessTokenInvalidError), + + #[error("The response received was invalid and could not be processed")] + InvalidResponse, + + #[error("Cryptography error, {0}")] + Crypto(#[from] bitwarden_crypto::CryptoError), + + #[error("Error parsing Identity response: {0}")] + IdentityFail(crate::auth::api::response::IdentityTokenFailResponse), + + #[error(transparent)] + Reqwest(#[from] reqwest::Error), + #[error(transparent)] + Serde(#[from] serde_json::Error), + #[error(transparent)] + Io(#[from] std::io::Error), + #[error(transparent)] + InvalidBase64(#[from] base64::DecodeError), + #[error(transparent)] + Chrono(#[from] chrono::ParseError), + + #[error("Received error message from server: [{}] {}", .status, .message)] + ResponseContent { status: StatusCode, message: String }, + + #[error("The state file version is invalid")] + InvalidStateFileVersion, + + #[error("The state file could not be read")] + InvalidStateFile, + + #[error("Internal error: {0}")] + Internal(Cow<'static, str>), +} + +impl From for Error { + fn from(s: String) -> Self { + Self::Internal(s.into()) + } +} + +impl From<&'static str> for Error { + fn from(s: &'static str) -> Self { + Self::Internal(s.into()) + } +} + +#[derive(Debug, Error)] +pub enum AccessTokenInvalidError { + #[error("Doesn't contain a decryption key")] + NoKey, + #[error("Has the wrong number of parts")] + WrongParts, + #[error("Is the wrong version")] + WrongVersion, + #[error("Has an invalid identifier")] + InvalidUuid, + + #[error("Error decoding base64: {0}")] + InvalidBase64(#[from] base64::DecodeError), + + #[error("Invalid base64 length: expected {expected}, got {got}")] + InvalidBase64Length { expected: usize, got: usize }, +} + +// Ensure that the error messages implement Send and Sync +#[cfg(test)] +const _: () = { + fn assert_send() {} + fn assert_sync() {} + fn assert_all() { + assert_send::(); + assert_sync::(); + } +}; + +macro_rules! impl_bitwarden_error { + ($name:ident) => { + impl From<$name> for Error { + fn from(e: $name) -> Self { + match e { + $name::Reqwest(e) => Self::Reqwest(e), + $name::ResponseError(e) => Self::ResponseContent { + status: e.status, + message: e.content, + }, + $name::Serde(e) => Self::Serde(e), + $name::Io(e) => Self::Io(e), + } + } + } + }; +} +impl_bitwarden_error!(ApiError); +impl_bitwarden_error!(IdentityError); + +pub(crate) type Result = std::result::Result; + #[derive(Debug, Error)] #[error("The response received was missing a required field: {0}")] pub struct MissingFieldError(pub &'static str); diff --git a/crates/bitwarden-core/src/lib.rs b/crates/bitwarden-core/src/lib.rs index 9d701730c..409f0133b 100644 --- a/crates/bitwarden-core/src/lib.rs +++ b/crates/bitwarden-core/src/lib.rs @@ -3,5 +3,20 @@ uniffi::setup_scaffolding!(); #[cfg(feature = "uniffi")] mod uniffi_support; +#[cfg(feature = "internal")] +pub mod admin_console; +pub mod auth; +pub mod client; mod error; +pub use error::Error; +#[cfg(feature = "internal")] +pub mod mobile; pub use error::{MissingFieldError, VaultLocked}; +#[cfg(feature = "internal")] +pub mod platform; +#[cfg(feature = "secrets")] +pub mod secrets_manager; +mod util; + +pub use bitwarden_crypto::ZeroizingAllocator; +pub use client::{Client, ClientSettings, DeviceType}; 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 80% rename from crates/bitwarden/src/mobile/client_kdf.rs rename to crates/bitwarden-core/src/mobile/client_kdf.rs index 4e62e5d59..5ec7aec77 100644 --- a/crates/bitwarden/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/src/mobile/crypto.rs b/crates/bitwarden-core/src/mobile/crypto.rs similarity index 90% rename from crates/bitwarden/src/mobile/crypto.rs rename to crates/bitwarden-core/src/mobile/crypto.rs index fde041e5f..2b6992496 100644 --- a/crates/bitwarden/src/mobile/crypto.rs +++ b/crates/bitwarden-core/src/mobile/crypto.rs @@ -1,18 +1,16 @@ use std::collections::HashMap; -use bitwarden_core::VaultLocked; 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, + Client, VaultLocked, }; #[cfg(feature = "internal")] @@ -99,18 +97,26 @@ pub async fn initialize_user_crypto(client: &Client, req: InitUserCryptoRequest) 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, @@ -129,7 +135,9 @@ pub async fn initialize_user_crypto(client: &Client, req: InitUserCryptoRequest) 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, @@ -140,17 +148,21 @@ pub async fn initialize_user_crypto(client: &Client, req: InitUserCryptoRequest) 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(()) } @@ -167,13 +179,13 @@ pub struct InitOrgCryptoRequest { #[cfg(feature = "internal")] pub async fn initialize_org_crypto(client: &Client, req: InitOrgCryptoRequest) -> Result<()> { let organization_keys = req.organization_keys.into_iter().collect(); - client.initialize_org_crypto(organization_keys)?; + client.internal.initialize_org_crypto(organization_keys)?; Ok(()) } #[cfg(feature = "internal")] pub async fn get_user_encryption_key(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(VaultLocked)?; Ok(user_key.to_base64()) @@ -191,10 +203,13 @@ pub struct UpdatePasswordResponse { } pub fn update_password(client: &Client, new_password: String) -> Result { - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let user_key = enc.get_key(&None).ok_or(VaultLocked)?; - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; + let login_method = client + .internal + .get_login_method() + .ok_or(Error::NotAuthenticated)?; // Derive a new master key from password let new_master_key = match login_method.as_ref() { @@ -202,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)?; @@ -231,10 +247,13 @@ pub struct DerivePinKeyResponse { #[cfg(feature = "internal")] pub fn derive_pin_key(client: &Client, pin: String) -> Result { - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let user_key = enc.get_key(&None).ok_or(VaultLocked)?; - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; + let login_method = client + .internal + .get_login_method() + .ok_or(Error::NotAuthenticated)?; let pin_protected_user_key = derive_pin_protected_user_key(&pin, &login_method, user_key)?; @@ -246,11 +265,14 @@ pub fn derive_pin_key(client: &Client, pin: String) -> Result Result { - let enc = client.get_encryption_settings()?; + let enc = client.internal.get_encryption_settings()?; let user_key = enc.get_key(&None).ok_or(VaultLocked)?; let pin: String = encrypted_pin.decrypt_with_key(user_key)?; - let login_method = client.get_login_method().ok_or(Error::NotAuthenticated)?; + let login_method = client + .internal + .get_login_method() + .ok_or(Error::NotAuthenticated)?; derive_pin_protected_user_key(&pin, &login_method, user_key) } @@ -266,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)?) @@ -281,7 +304,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(VaultLocked)?; Ok(AsymmetricEncString::encrypt_rsa2048_oaep_sha1( @@ -293,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() { @@ -354,12 +377,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) @@ -414,12 +439,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) @@ -451,12 +478,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) @@ -487,6 +516,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(); @@ -499,7 +529,7 @@ mod tests { AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key).unwrap()).unwrap(); let decrypted: Vec = encrypted.decrypt_with_key(&private_key).unwrap(); - let enc = client.get_encryption_settings().unwrap(); + let enc = client.internal.get_encryption_settings().unwrap(); let expected = enc.get_key(&None).unwrap(); assert_eq!(&decrypted, &expected.to_vec()); } 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 82% rename from crates/bitwarden/src/mobile/mod.rs rename to crates/bitwarden-core/src/mobile/mod.rs index 9425116e5..7c6a916a8 100644 --- a/crates/bitwarden/src/mobile/mod.rs +++ b/crates/bitwarden-core/src/mobile/mod.rs @@ -1,7 +1,5 @@ pub mod crypto; pub mod kdf; -pub mod tool; -pub mod vault; mod client_crypto; mod client_kdf; diff --git a/crates/bitwarden/src/platform/client_platform.rs b/crates/bitwarden-core/src/platform/client_platform.rs similarity index 81% rename from crates/bitwarden/src/platform/client_platform.rs rename to crates/bitwarden-core/src/platform/client_platform.rs index ca9ce8d63..1f117d5fe 100644 --- a/crates/bitwarden/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, @@ -26,13 +24,6 @@ impl<'a> ClientPlatform<'a> { ) -> Result { get_user_api_key(self.client, &input).await } - - #[cfg(feature = "uniffi")] - pub fn fido2(&'a self) -> ClientFido2<'a> { - ClientFido2 { - client: self.client, - } - } } impl<'a> Client { diff --git a/crates/bitwarden/src/platform/generate_fingerprint.rs b/crates/bitwarden-core/src/platform/generate_fingerprint.rs similarity index 96% rename from crates/bitwarden/src/platform/generate_fingerprint.rs rename to crates/bitwarden-core/src/platform/generate_fingerprint.rs index 521a75c01..6ac41e149 100644 --- a/crates/bitwarden/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() @@ -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() { @@ -75,6 +77,7 @@ mod tests { .unwrap(); client + .internal .initialize_user_crypto_master_key( master_key, user_key.parse().unwrap(), 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 90% rename from crates/bitwarden/src/platform/get_user_api_key.rs rename to crates/bitwarden-core/src/platform/get_user_api_key.rs index 991040aaf..dcdafa0b4 100644 --- a/crates/bitwarden/src/platform/get_user_api_key.rs +++ b/crates/bitwarden-core/src/platform/get_user_api_key.rs @@ -4,7 +4,6 @@ use bitwarden_api_api::{ apis::accounts_api::accounts_api_key_post, models::{ApiKeyResponseModel, SecretVerificationRequestModel}, }; -use bitwarden_core::require; use bitwarden_crypto::{HashPurpose, MasterKey}; use log::{debug, info}; use schemars::JsonSchema; @@ -14,7 +13,7 @@ use super::SecretVerificationRequest; use crate::{ client::{LoginMethod, UserLoginMethod}, error::{Error, Result}, - Client, + require, Client, }; pub(crate) async fn get_user_api_key( @@ -27,15 +26,18 @@ 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> { - if client.is_authed() { - client.get_login_method().ok_or(Error::NotAuthenticated) + if client.internal.is_authed() { + client + .internal + .get_login_method() + .ok_or(Error::NotAuthenticated) } else { Err(Error::NotAuthenticated) } diff --git a/crates/bitwarden/src/platform/mod.rs b/crates/bitwarden-core/src/platform/mod.rs similarity index 63% rename from crates/bitwarden/src/platform/mod.rs rename to crates/bitwarden-core/src/platform/mod.rs index 82d341e6e..031554be0 100644 --- a/crates/bitwarden/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,10 +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::*; - - pub use super::client_fido::DecryptFido2AutofillCredentialsError; -} 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-core/src/secrets_manager/mod.rs b/crates/bitwarden-core/src/secrets_manager/mod.rs new file mode 100644 index 000000000..266c62acc --- /dev/null +++ b/crates/bitwarden-core/src/secrets_manager/mod.rs @@ -0,0 +1 @@ +pub mod state; 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-core/src/uniffi_support.rs b/crates/bitwarden-core/src/uniffi_support.rs index 320df6cb5..fcdd2aa78 100644 --- a/crates/bitwarden-core/src/uniffi_support.rs +++ b/crates/bitwarden-core/src/uniffi_support.rs @@ -1,7 +1,18 @@ +use std::num::NonZeroU32; + +use bitwarden_crypto::{AsymmetricEncString, EncString}; use uuid::Uuid; use crate::UniffiCustomTypeConverter; +uniffi::ffi_converter_forward!(NonZeroU32, bitwarden_crypto::UniFfiTag, crate::UniFfiTag); +uniffi::ffi_converter_forward!(EncString, bitwarden_crypto::UniFfiTag, crate::UniFfiTag); +uniffi::ffi_converter_forward!( + AsymmetricEncString, + bitwarden_crypto::UniFfiTag, + crate::UniFfiTag +); + type DateTime = chrono::DateTime; uniffi::custom_type!(DateTime, std::time::SystemTime); 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/tests/register.rs b/crates/bitwarden-core/tests/register.rs similarity index 97% rename from crates/bitwarden/tests/register.rs rename to crates/bitwarden-core/tests/register.rs index 6e5ea9336..34f61ca3c 100644 --- a/crates/bitwarden/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-crypto/Cargo.toml b/crates/bitwarden-crypto/Cargo.toml index e03a8d5c1..9968460b8 100644 --- a/crates/bitwarden-crypto/Cargo.toml +++ b/crates/bitwarden-crypto/Cargo.toml @@ -25,7 +25,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 ac302526c..79e0abb22 100644 --- a/crates/bitwarden-exporters/Cargo.toml +++ b/crates/bitwarden-exporters/Cargo.toml @@ -14,8 +14,11 @@ repository.workspace = true license-file.workspace = true keywords.workspace = true +[features] +uniffi = ["dep:uniffi"] # Uniffi bindings + [dependencies] -base64 = ">=0.21.2, <0.23" +base64 = ">=0.22.1, <0.23" bitwarden-core = { workspace = true } bitwarden-crypto = { workspace = true } bitwarden-vault = { workspace = true } @@ -25,9 +28,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"] } [lints] diff --git a/crates/bitwarden/src/tool/exporters/client_exporter.rs b/crates/bitwarden-exporters/src/client_exporter.rs similarity index 52% rename from crates/bitwarden/src/tool/exporters/client_exporter.rs rename to crates/bitwarden-exporters/src/client_exporter.rs index 5257538cd..ffc9963c1 100644 --- a/crates/bitwarden/src/tool/exporters/client_exporter.rs +++ b/crates/bitwarden-exporters/src/client_exporter.rs @@ -1,23 +1,26 @@ +use bitwarden_core::Client; use bitwarden_vault::{Cipher, Collection, Folder}; use crate::{ - error::Result, - tool::exporters::{export_organization_vault, export_vault, ExportFormat}, - Client, + export::{export_organization_vault, export_vault}, + ExportError, ExportFormat, }; pub struct ClientExporters<'a> { - pub(crate) client: &'a crate::Client, + client: &'a Client, } impl<'a> ClientExporters<'a> { - /// **Draft:** Export the vault as a CSV, JSON, or encrypted JSON file. + fn new(client: &'a Client) -> Self { + Self { client } + } + pub fn export_vault( &self, folders: Vec, ciphers: Vec, format: ExportFormat, - ) -> Result { + ) -> Result { export_vault(self.client, folders, ciphers, format) } @@ -26,13 +29,17 @@ impl<'a> ClientExporters<'a> { collections: Vec, ciphers: Vec, format: ExportFormat, - ) -> Result { + ) -> Result { export_organization_vault(collections, ciphers, format) } } -impl<'a> Client { - pub fn exporters(&'a self) -> ClientExporters<'a> { - ClientExporters { client: self } +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/error.rs b/crates/bitwarden-exporters/src/error.rs new file mode 100644 index 000000000..d23819696 --- /dev/null +++ b/crates/bitwarden-exporters/src/error.rs @@ -0,0 +1,21 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum ExportError { + #[error(transparent)] + MissingField(#[from] bitwarden_core::MissingFieldError), + #[error(transparent)] + VaultLocked(#[from] bitwarden_core::VaultLocked), + + #[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(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..0721ae11f --- /dev/null +++ b/crates/bitwarden-exporters/src/export.rs @@ -0,0 +1,43 @@ +use bitwarden_core::{Client, VaultLocked}; +use bitwarden_crypto::KeyDecryptable; +use bitwarden_vault::{Cipher, CipherView, Collection, Folder, FolderView}; + +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.internal.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(); + + 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.internal.get_kdf()?, + )?), + } +} + +pub(crate) fn export_organization_vault( + _collections: Vec, + _ciphers: Vec, + _format: ExportFormat, +) -> Result { + todo!(); +} diff --git a/crates/bitwarden-exporters/src/lib.rs b/crates/bitwarden-exporters/src/lib.rs index e754a64d1..75b0503e2 100644 --- a/crates/bitwarden-exporters/src/lib.rs +++ b/crates/bitwarden-exporters/src/lib.rs @@ -1,22 +1,28 @@ use std::fmt; -use bitwarden_crypto::Kdf; use chrono::{DateTime, Utc}; -use thiserror::Error; +use schemars::JsonSchema; use uuid::Uuid; +#[cfg(feature = "uniffi")] +uniffi::setup_scaffolding!(); + +mod client_exporter; mod csv; -use crate::csv::export_csv; -mod json; -use json::export_json; mod encrypted_json; -use encrypted_json::export_encrypted_json; +mod json; mod models; - -pub enum Format { +pub use client_exporter::{ClientExporters, ClientExportersExt}; +mod error; +mod export; +pub use error::ExportError; + +#[derive(JsonSchema)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))] +pub enum ExportFormat { Csv, Json, - EncryptedJson { password: String, kdf: Kdf }, + EncryptedJson { password: String }, } /// Export representation of a Bitwarden folder. @@ -126,27 +132,3 @@ pub struct Identity { 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)?) - } - } -} diff --git a/crates/bitwarden/uniffi.toml b/crates/bitwarden-exporters/uniffi.toml similarity index 50% rename from crates/bitwarden/uniffi.toml rename to crates/bitwarden-exporters/uniffi.toml index c5fdba5c2..7a57dfabd 100644 --- a/crates/bitwarden/uniffi.toml +++ b/crates/bitwarden-exporters/uniffi.toml @@ -1,9 +1,9 @@ [bindings.kotlin] -package_name = "com.bitwarden.bitwarden" +package_name = "com.bitwarden.exporters" generate_immutable_records = true android = true [bindings.swift] -ffi_module_name = "BitwardenBitwardenFFI" -module_name = "BitwardenBitwarden" +ffi_module_name = "BitwardenExportersFFI" +module_name = "BitwardenExporters" generate_immutable_records = true diff --git a/crates/bitwarden-fido/Cargo.toml b/crates/bitwarden-fido/Cargo.toml index 3e02f544c..12c2b6b1d 100644 --- a/crates/bitwarden-fido/Cargo.toml +++ b/crates/bitwarden-fido/Cargo.toml @@ -14,11 +14,11 @@ 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" -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-fido/src/authenticator.rs b/crates/bitwarden-fido/src/authenticator.rs index 41f5d5b45..e86812bd9 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 std::sync::Mutex; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, VaultLocked}; use bitwarden_crypto::{CryptoError, KeyContainer, KeyEncryptable}; use bitwarden_vault::{CipherError, CipherView}; use itertools::Itertools; @@ -94,14 +94,8 @@ pub enum CredentialsForAutofillError { FromCipherViewError(#[from] Fido2CredentialAutofillViewError), } -/// 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, @@ -111,7 +105,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> { @@ -258,7 +252,7 @@ impl<'a> Fido2Authenticator<'a> { &mut self, rp_id: String, ) -> Result, SilentlyDiscoverCredentialsError> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let result = self.credential_store.find_credentials(None, rp_id).await?; result @@ -277,7 +271,7 @@ impl<'a> Fido2Authenticator<'a> { pub async fn credentials_for_autofill( &mut self, ) -> Result, CredentialsForAutofillError> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let all_credentials = self.credential_store.all_credentials().await?; all_credentials @@ -322,7 +316,7 @@ impl<'a> Fido2Authenticator<'a> { pub(super) fn get_selected_credential( &self, ) -> Result { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; let cipher = self .selected_cipher @@ -385,7 +379,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 @@ -461,7 +459,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { user: passkey::types::ctap2::make_credential::PublicKeyCredentialUserEntity, rp: passkey::types::ctap2::make_credential::PublicKeyCredentialRpEntity, ) -> Result<(), InnerError> { - let enc = this.authenticator.client.get_encryption_settings()?; + let enc = this + .authenticator + .client + .internal + .get_encryption_settings()?; let cred = try_from_credential_full(cred, user, rp)?; @@ -529,7 +531,11 @@ impl passkey::authenticator::CredentialStore for CredentialStoreImpl<'_> { this: &mut CredentialStoreImpl<'_>, cred: Passkey, ) -> Result<(), InnerError> { - 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/src/platform/client_fido.rs b/crates/bitwarden-fido/src/client_fido.rs similarity index 71% rename from crates/bitwarden/src/platform/client_fido.rs rename to crates/bitwarden-fido/src/client_fido.rs index 79164b48f..84b3de6a1 100644 --- a/crates/bitwarden/src/platform/client_fido.rs +++ b/crates/bitwarden-fido/src/client_fido.rs @@ -1,13 +1,11 @@ -use std::sync::Arc; - -use bitwarden_fido::{ - Fido2Authenticator, Fido2Client, Fido2CredentialAutofillView, Fido2CredentialStore, - Fido2UserInterface, FidoEncryptionSettingStore, -}; +use bitwarden_core::Client; use bitwarden_vault::CipherView; use thiserror::Error; -use crate::Client; +use crate::{ + Fido2Authenticator, Fido2Client, Fido2CredentialAutofillView, Fido2CredentialAutofillViewError, + Fido2CredentialStore, Fido2UserInterface, +}; pub struct ClientFido2<'a> { #[allow(dead_code)] @@ -19,18 +17,14 @@ pub enum DecryptFido2AutofillCredentialsError { #[error(transparent)] VaultLocked(#[from] bitwarden_core::VaultLocked), #[error(transparent)] - Fido2CredentialAutofillViewError(#[from] bitwarden_fido::Fido2CredentialAutofillViewError), + Fido2CredentialAutofillViewError(#[from] Fido2CredentialAutofillViewError), } -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, @@ -53,7 +47,7 @@ impl<'a> ClientFido2<'a> { &'a self, cipher_view: CipherView, ) -> Result, DecryptFido2AutofillCredentialsError> { - let enc = self.client.get_encryption_settings()?; + let enc = self.client.internal.get_encryption_settings()?; Ok(Fido2CredentialAutofillView::from_cipher_view( &cipher_view, @@ -61,3 +55,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 b572eef36..830b5cfdf 100644 --- a/crates/bitwarden-fido/src/lib.rs +++ b/crates/bitwarden-fido/src/lib.rs @@ -13,14 +13,16 @@ mod uniffi_support; mod authenticator; mod client; +mod client_fido; mod crypto; mod traits; mod types; pub use authenticator::{ - CredentialsForAutofillError, Fido2Authenticator, FidoEncryptionSettingStore, GetAssertionError, - MakeCredentialError, SilentlyDiscoverCredentialsError, + CredentialsForAutofillError, Fido2Authenticator, GetAssertionError, MakeCredentialError, + SilentlyDiscoverCredentialsError, }; pub use client::{Fido2Client, Fido2ClientError}; +pub use client_fido::{ClientFido2, ClientFido2Ext, DecryptFido2AutofillCredentialsError}; pub use passkey::authenticator::UIHint; use thiserror::Error; pub use traits::{ diff --git a/crates/bitwarden-generators/Cargo.toml b/crates/bitwarden-generators/Cargo.toml index 6934f681e..629722548 100644 --- a/crates/bitwarden-generators/Cargo.toml +++ b/crates/bitwarden-generators/Cargo.toml @@ -17,6 +17,7 @@ keywords.workspace = true uniffi = ["dep:uniffi"] # Uniffi bindings [dependencies] +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/src/tool/client_generator.rs b/crates/bitwarden-generators/src/client_generator.rs similarity index 63% rename from crates/bitwarden/src/tool/client_generator.rs rename to crates/bitwarden-generators/src/client_generator.rs index fe5319fc7..e5bad6f29 100644 --- a/crates/bitwarden/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. @@ -18,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, @@ -32,8 +37,8 @@ impl<'a> ClientGenerator<'a> { /// Ok(()) /// } /// ``` - pub fn password(&self, input: PasswordGeneratorRequest) -> Result { - Ok(password(input)?) + pub fn password(&self, input: PasswordGeneratorRequest) -> Result { + password(input) } /// Generates a random passphrase. @@ -46,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() @@ -57,8 +64,8 @@ impl<'a> ClientGenerator<'a> { /// Ok(()) /// } /// ``` - pub fn passphrase(&self, input: PassphraseGeneratorRequest) -> Result { - Ok(passphrase(input)?) + pub fn passphrase(&self, input: PassphraseGeneratorRequest) -> Result { + passphrase(input) } /// Generates a random username. @@ -69,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, @@ -80,13 +89,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.internal.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 2584382f1..0ebd20295 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 = "uniffi")] diff --git a/crates/bitwarden-json/src/client.rs b/crates/bitwarden-json/src/client.rs index dd3469c45..536693663 100644 --- a/crates/bitwarden-json/src/client.rs +++ b/crates/bitwarden-json/src/client.rs @@ -1,3 +1,7 @@ +#[cfg(feature = "secrets")] +use bitwarden::secrets_manager::{ClientProjectsExt, ClientSecretsExt}; +#[cfg(feature = "internal")] +use bitwarden::vault::ClientVaultExt; use bitwarden::ClientSettings; #[cfg(feature = "secrets")] 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/src/mobile/tool/client_sends.rs b/crates/bitwarden-send/src/client_sends.rs similarity index 65% rename from crates/bitwarden/src/mobile/tool/client_sends.rs rename to crates/bitwarden-send/src/client_sends.rs index 38a7d072d..da1c527f0 100644 --- a/crates/bitwarden/src/mobile/tool/client_sends.rs +++ b/crates/bitwarden-send/src/client_sends.rs @@ -1,21 +1,21 @@ use std::path::Path; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable}; -use crate::{ - error::Result, - tool::{Send, SendListView, SendView}, - Client, -}; +use crate::{Send, SendListView, SendView}; pub struct ClientSends<'a> { - pub(crate) client: &'a Client, + client: &'a Client, } impl<'a> ClientSends<'a> { - pub fn decrypt(&self, send: Send) -> Result { - let enc = self.client.get_encryption_settings()?; + fn new(client: &'a Client) -> Self { + Self { client } + } + + pub fn decrypt(&self, send: Send) -> Result { + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(VaultLocked)?; let send_view = send.decrypt_with_key(key)?; @@ -23,8 +23,8 @@ impl<'a> ClientSends<'a> { Ok(send_view) } - pub fn decrypt_list(&self, sends: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_list(&self, sends: Vec) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(VaultLocked)?; let send_views = sends.decrypt_with_key(key)?; @@ -37,15 +37,15 @@ impl<'a> ClientSends<'a> { send: Send, encrypted_file_path: &Path, decrypted_file_path: &Path, - ) -> Result<()> { + ) -> Result<(), Error> { let data = std::fs::read(encrypted_file_path)?; let decrypted = self.decrypt_buffer(send, &data)?; std::fs::write(decrypted_file_path, decrypted)?; Ok(()) } - pub fn decrypt_buffer(&self, send: Send, encrypted_buffer: &[u8]) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_buffer(&self, send: Send, encrypted_buffer: &[u8]) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(VaultLocked)?; let key = Send::get_key(&send.key, key)?; @@ -53,8 +53,8 @@ impl<'a> ClientSends<'a> { Ok(buf.decrypt_with_key(&key)?) } - pub fn encrypt(&self, send_view: SendView) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn encrypt(&self, send_view: SendView) -> Result { + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(VaultLocked)?; let send = send_view.encrypt_with_key(key)?; @@ -67,15 +67,15 @@ impl<'a> ClientSends<'a> { send: Send, decrypted_file_path: &Path, encrypted_file_path: &Path, - ) -> Result<()> { + ) -> Result<(), Error> { let data = std::fs::read(decrypted_file_path)?; let encrypted = self.encrypt_buffer(send, &data)?; std::fs::write(encrypted_file_path, encrypted)?; Ok(()) } - pub fn encrypt_buffer(&self, send: Send, buffer: &[u8]) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn encrypt_buffer(&self, send: Send, buffer: &[u8]) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; let key = enc.get_key(&None).ok_or(VaultLocked)?; let key = Send::get_key(&send.key, key)?; @@ -84,8 +84,12 @@ impl<'a> ClientSends<'a> { } } -impl<'a> Client { - pub fn sends(&'a 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 index b2bbf6e86..e29d7305f 100644 --- a/crates/bitwarden-send/src/lib.rs +++ b/crates/bitwarden-send/src/lib.rs @@ -5,5 +5,7 @@ mod uniffi_support; mod error; pub use error::SendParseError; +mod client_sends; +pub use client_sends::{ClientSends, ClientSendsExt}; mod send; pub use send::{Send, SendListView, SendView}; diff --git a/crates/bitwarden-send/src/send.rs b/crates/bitwarden-send/src/send.rs index 0ada20147..452032cf6 100644 --- a/crates/bitwarden-send/src/send.rs +++ b/crates/bitwarden-send/src/send.rs @@ -15,7 +15,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use uuid::Uuid; use zeroize::Zeroizing; -use crate::error::SendParseError; +use crate::SendParseError; const SEND_ITERATIONS: u32 = 100_000; diff --git a/crates/bitwarden-sm/Cargo.toml b/crates/bitwarden-sm/Cargo.toml new file mode 100644 index 000000000..6580dcf0f --- /dev/null +++ b/crates/bitwarden-sm/Cargo.toml @@ -0,0 +1,32 @@ +[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", +], 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"] } + +[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..13b2c6967 --- /dev/null +++ b/crates/bitwarden-sm/src/client_projects.rs @@ -0,0 +1,50 @@ +use bitwarden_core::{Client, Error}; + +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 Client, +} + +impl<'a> ClientProjects<'a> { + pub fn new(client: &'a Client) -> Self { + Self { client } + } + + pub async fn get(&self, input: &ProjectGetRequest) -> Result { + get_project(self.client, input).await + } + + pub async fn create(&self, input: &ProjectCreateRequest) -> Result { + create_project(self.client, input).await + } + + pub async fn list(&self, input: &ProjectsListRequest) -> Result { + list_projects(self.client, input).await + } + + pub async fn update(&self, input: &ProjectPutRequest) -> Result { + update_project(self.client, input).await + } + + pub async fn delete( + &self, + input: ProjectsDeleteRequest, + ) -> Result { + delete_projects(self.client, input).await + } +} + +pub trait ClientProjectsExt<'a> { + fn projects(&'a self) -> ClientProjects<'a>; +} + +impl<'a> ClientProjectsExt<'a> for Client { + 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 new file mode 100644 index 000000000..2b1085a0a --- /dev/null +++ b/crates/bitwarden-sm/src/client_secrets.rs @@ -0,0 +1,70 @@ +use bitwarden_core::{Client, Error}; + +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 Client, +} + +impl<'a> ClientSecrets<'a> { + pub fn new(client: &'a Client) -> Self { + Self { client } + } + + pub async fn get(&self, input: &SecretGetRequest) -> Result { + get_secret(self.client, input).await + } + + pub async fn get_by_ids(&self, input: SecretsGetRequest) -> Result { + get_secrets_by_ids(self.client, input).await + } + + pub async fn create(&self, input: &SecretCreateRequest) -> Result { + create_secret(self.client, input).await + } + + pub async fn list( + &self, + input: &SecretIdentifiersRequest, + ) -> Result { + list_secrets(self.client, input).await + } + + pub async fn list_by_project( + &self, + input: &SecretIdentifiersByProjectRequest, + ) -> Result { + list_secrets_by_project(self.client, input).await + } + + pub async fn update(&self, input: &SecretPutRequest) -> Result { + update_secret(self.client, input).await + } + + pub async fn delete( + &self, + input: SecretsDeleteRequest, + ) -> Result { + delete_secrets(self.client, input).await + } + + pub async fn sync(&self, input: &SecretsSyncRequest) -> Result { + sync_secrets(self.client, input).await + } +} + +pub trait ClientSecretsExt<'a> { + fn secrets(&'a self) -> ClientSecrets<'a>; +} + +impl<'a> ClientSecretsExt<'a> for Client { + fn secrets(&'a 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..6f44bd16d --- /dev/null +++ b/crates/bitwarden-sm/src/lib.rs @@ -0,0 +1,7 @@ +mod client_projects; +mod client_secrets; +pub mod projects; +pub mod secrets; + +pub use client_projects::{ClientProjects, ClientProjectsExt}; +pub use client_secrets::{ClientSecrets, ClientSecretsExt}; diff --git a/crates/bitwarden/src/secrets_manager/projects/create.rs b/crates/bitwarden-sm/src/projects/create.rs similarity index 82% rename from crates/bitwarden/src/secrets_manager/projects/create.rs rename to crates/bitwarden-sm/src/projects/create.rs index 824a9f3df..bacec3cef 100644 --- a/crates/bitwarden/src/secrets_manager/projects/create.rs +++ b/crates/bitwarden-sm/src/projects/create.rs @@ -1,12 +1,11 @@ use bitwarden_api_api::models::ProjectCreateRequestModel; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -20,8 +19,8 @@ pub struct ProjectCreateRequest { pub(crate) async fn create_project( client: &Client, input: &ProjectCreateRequest, -) -> Result { - let enc = client.get_encryption_settings()?; +) -> Result { + let enc = client.internal.get_encryption_settings()?; let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -30,7 +29,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, diff --git a/crates/bitwarden/src/secrets_manager/projects/delete.rs b/crates/bitwarden-sm/src/projects/delete.rs similarity index 86% rename from crates/bitwarden/src/secrets_manager/projects/delete.rs rename to crates/bitwarden-sm/src/projects/delete.rs index 644666e35..27e7f83e7 100644 --- a/crates/bitwarden/src/secrets_manager/projects/delete.rs +++ b/crates/bitwarden-sm/src/projects/delete.rs @@ -1,13 +1,11 @@ use bitwarden_api_api::models::{ BulkDeleteResponseModel, BulkDeleteResponseModelListResponseModel, }; -use bitwarden_core::require; +use bitwarden_core::{client::Client, require, Error}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{client::Client, error::Result}; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProjectsDeleteRequest { @@ -18,8 +16,8 @@ pub struct ProjectsDeleteRequest { pub(crate) async fn delete_projects( client: &Client, input: ProjectsDeleteRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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?; @@ -36,7 +34,7 @@ pub struct ProjectsDeleteResponse { impl ProjectsDeleteResponse { pub(crate) fn process_response( response: BulkDeleteResponseModelListResponseModel, - ) -> Result { + ) -> Result { Ok(ProjectsDeleteResponse { data: response .data @@ -58,7 +56,7 @@ pub struct ProjectDeleteResponse { impl ProjectDeleteResponse { pub(crate) fn process_response( response: BulkDeleteResponseModel, - ) -> Result { + ) -> Result { Ok(ProjectDeleteResponse { id: require!(response.id), error: response.error, diff --git a/crates/bitwarden/src/secrets_manager/projects/get.rs b/crates/bitwarden-sm/src/projects/get.rs similarity index 72% rename from crates/bitwarden/src/secrets_manager/projects/get.rs rename to crates/bitwarden-sm/src/projects/get.rs index 9eaf9f104..81a669739 100644 --- a/crates/bitwarden/src/secrets_manager/projects/get.rs +++ b/crates/bitwarden-sm/src/projects/get.rs @@ -1,9 +1,9 @@ +use bitwarden_core::{client::Client, Error}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -15,12 +15,12 @@ pub struct ProjectGetRequest { pub(crate) async fn get_project( client: &Client, input: &ProjectGetRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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/src/secrets_manager/projects/list.rs b/crates/bitwarden-sm/src/projects/list.rs similarity index 85% rename from crates/bitwarden/src/secrets_manager/projects/list.rs rename to crates/bitwarden-sm/src/projects/list.rs index 4cb50b7a7..334e06007 100644 --- a/crates/bitwarden/src/secrets_manager/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, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{ - client::{encryption_settings::EncryptionSettings, Client}, - error::Result, -}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -19,15 +19,15 @@ pub struct ProjectsListRequest { pub(crate) async fn list_projects( client: &Client, input: &ProjectsListRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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) } @@ -42,7 +42,7 @@ impl ProjectsResponse { pub(crate) fn process_response( response: ProjectResponseModelListResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let data = response.data.unwrap_or_default(); Ok(ProjectsResponse { diff --git a/crates/bitwarden/src/secrets_manager/projects/mod.rs b/crates/bitwarden-sm/src/projects/mod.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/projects/mod.rs rename to crates/bitwarden-sm/src/projects/mod.rs diff --git a/crates/bitwarden/src/secrets_manager/projects/project_response.rs b/crates/bitwarden-sm/src/projects/project_response.rs similarity index 90% rename from crates/bitwarden/src/secrets_manager/projects/project_response.rs rename to crates/bitwarden-sm/src/projects/project_response.rs index e8cac63fd..b0ad1728f 100644 --- a/crates/bitwarden/src/secrets_manager/projects/project_response.rs +++ b/crates/bitwarden-sm/src/projects/project_response.rs @@ -1,13 +1,11 @@ use bitwarden_api_api::models::ProjectResponseModel; -use bitwarden_core::require; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, require, Error}; use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{client::encryption_settings::EncryptionSettings, error::Result}; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct ProjectResponse { @@ -22,7 +20,7 @@ impl ProjectResponse { pub(crate) fn process_response( response: ProjectResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let organization_id = require!(response.organization_id); let enc_key = enc .get_key(&Some(organization_id)) diff --git a/crates/bitwarden/src/secrets_manager/projects/update.rs b/crates/bitwarden-sm/src/projects/update.rs similarity index 82% rename from crates/bitwarden/src/secrets_manager/projects/update.rs rename to crates/bitwarden-sm/src/projects/update.rs index 1a6e963c0..759edff99 100644 --- a/crates/bitwarden/src/secrets_manager/projects/update.rs +++ b/crates/bitwarden-sm/src/projects/update.rs @@ -1,12 +1,11 @@ use bitwarden_api_api::models::ProjectUpdateRequestModel; -use bitwarden_core::VaultLocked; +use bitwarden_core::{client::Client, Error, VaultLocked}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::ProjectResponse; -use crate::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -22,8 +21,8 @@ pub struct ProjectPutRequest { pub(crate) async fn update_project( client: &Client, input: &ProjectPutRequest, -) -> Result { - let enc = client.get_encryption_settings()?; +) -> Result { + let enc = client.internal.get_encryption_settings()?; let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -32,7 +31,7 @@ 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?; diff --git a/crates/bitwarden/src/secrets_manager/secrets/create.rs b/crates/bitwarden-sm/src/secrets/create.rs similarity index 86% rename from crates/bitwarden/src/secrets_manager/secrets/create.rs rename to crates/bitwarden-sm/src/secrets/create.rs index a3124e657..3e83d390d 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/create.rs +++ b/crates/bitwarden-sm/src/secrets/create.rs @@ -1,12 +1,11 @@ use bitwarden_api_api::models::SecretCreateRequestModel; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -25,8 +24,8 @@ pub struct SecretCreateRequest { pub(crate) async fn create_secret( client: &Client, input: &SecretCreateRequest, -) -> Result { - let enc = client.get_encryption_settings()?; +) -> Result { + let enc = client.internal.get_encryption_settings()?; let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -38,7 +37,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, diff --git a/crates/bitwarden/src/secrets_manager/secrets/delete.rs b/crates/bitwarden-sm/src/secrets/delete.rs similarity index 86% rename from crates/bitwarden/src/secrets_manager/secrets/delete.rs rename to crates/bitwarden-sm/src/secrets/delete.rs index fa019c731..377d19f62 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/delete.rs +++ b/crates/bitwarden-sm/src/secrets/delete.rs @@ -1,13 +1,11 @@ use bitwarden_api_api::models::{ BulkDeleteResponseModel, BulkDeleteResponseModelListResponseModel, }; -use bitwarden_core::require; +use bitwarden_core::{client::Client, require, Error}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{client::Client, error::Result}; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretsDeleteRequest { @@ -18,8 +16,8 @@ pub struct SecretsDeleteRequest { pub(crate) async fn delete_secrets( client: &Client, input: SecretsDeleteRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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?; @@ -36,7 +34,7 @@ pub struct SecretsDeleteResponse { impl SecretsDeleteResponse { pub(crate) fn process_response( response: BulkDeleteResponseModelListResponseModel, - ) -> Result { + ) -> Result { Ok(SecretsDeleteResponse { data: response .data @@ -58,7 +56,7 @@ pub struct SecretDeleteResponse { impl SecretDeleteResponse { pub(crate) fn process_response( response: BulkDeleteResponseModel, - ) -> Result { + ) -> Result { Ok(SecretDeleteResponse { id: require!(response.id), error: response.error, diff --git a/crates/bitwarden/src/secrets_manager/secrets/get.rs b/crates/bitwarden-sm/src/secrets/get.rs similarity index 73% rename from crates/bitwarden/src/secrets_manager/secrets/get.rs rename to crates/bitwarden-sm/src/secrets/get.rs index a9d285aa7..d0964df2e 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/get.rs +++ b/crates/bitwarden-sm/src/secrets/get.rs @@ -1,9 +1,9 @@ +use bitwarden_core::{Client, Error}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -15,11 +15,11 @@ pub struct SecretGetRequest { pub(crate) async fn get_secret( client: &Client, input: &SecretGetRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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/src/secrets_manager/secrets/get_by_ids.rs b/crates/bitwarden-sm/src/secrets/get_by_ids.rs similarity index 77% rename from crates/bitwarden/src/secrets_manager/secrets/get_by_ids.rs rename to crates/bitwarden-sm/src/secrets/get_by_ids.rs index 6ce3eeac8..b5714c4b7 100644 --- a/crates/bitwarden/src/secrets_manager/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}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretsResponse; -use crate::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -16,15 +16,15 @@ pub struct SecretsGetRequest { pub(crate) async fn get_secrets_by_ids( client: &Client, input: SecretsGetRequest, -) -> Result { +) -> 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/src/secrets_manager/secrets/list.rs b/crates/bitwarden-sm/src/secrets/list.rs similarity index 85% rename from crates/bitwarden/src/secrets_manager/secrets/list.rs rename to crates/bitwarden-sm/src/secrets/list.rs index 3d7af09df..9de4b9a47 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/list.rs +++ b/crates/bitwarden-sm/src/secrets/list.rs @@ -1,17 +1,15 @@ use bitwarden_api_api::models::{ SecretWithProjectsListResponseModel, SecretsWithProjectsInnerSecret, }; -use bitwarden_core::require; +use bitwarden_core::{ + client::{encryption_settings::EncryptionSettings, Client}, + require, Error, +}; use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{ - client::{encryption_settings::EncryptionSettings, Client}, - error::Result, -}; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretIdentifiersRequest { @@ -22,15 +20,15 @@ pub struct SecretIdentifiersRequest { pub(crate) async fn list_secrets( client: &Client, input: &SecretIdentifiersRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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,15 +43,15 @@ pub struct SecretIdentifiersByProjectRequest { pub(crate) async fn list_secrets_by_project( client: &Client, input: &SecretIdentifiersByProjectRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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) } @@ -68,7 +66,7 @@ impl SecretIdentifiersResponse { pub(crate) fn process_response( response: SecretWithProjectsListResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { Ok(SecretIdentifiersResponse { data: response .secrets @@ -93,7 +91,7 @@ impl SecretIdentifierResponse { pub(crate) fn process_response( response: SecretsWithProjectsInnerSecret, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let organization_id = require!(response.organization_id); let enc_key = enc .get_key(&Some(organization_id)) diff --git a/crates/bitwarden/src/secrets_manager/secrets/mod.rs b/crates/bitwarden-sm/src/secrets/mod.rs similarity index 100% rename from crates/bitwarden/src/secrets_manager/secrets/mod.rs rename to crates/bitwarden-sm/src/secrets/mod.rs diff --git a/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs b/crates/bitwarden-sm/src/secrets/secret_response.rs similarity index 93% rename from crates/bitwarden/src/secrets_manager/secrets/secret_response.rs rename to crates/bitwarden-sm/src/secrets/secret_response.rs index 4f306078d..138279b11 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/secret_response.rs +++ b/crates/bitwarden-sm/src/secrets/secret_response.rs @@ -1,15 +1,13 @@ use bitwarden_api_api::models::{ BaseSecretResponseModel, BaseSecretResponseModelListResponseModel, SecretResponseModel, }; -use bitwarden_core::require; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, require, Error}; use bitwarden_crypto::{CryptoError, EncString, KeyDecryptable}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; -use crate::{client::encryption_settings::EncryptionSettings, error::Result}; - #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct SecretResponse { @@ -29,7 +27,7 @@ impl SecretResponse { pub(crate) fn process_response( response: SecretResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let base = BaseSecretResponseModel { object: response.object, id: response.id, @@ -46,7 +44,7 @@ impl SecretResponse { pub(crate) fn process_base_response( response: BaseSecretResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let org_id = response.organization_id; let enc_key = enc.get_key(&org_id).ok_or(CryptoError::MissingKey)?; @@ -89,7 +87,7 @@ impl SecretsResponse { pub(crate) fn process_response( response: BaseSecretResponseModelListResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { Ok(SecretsResponse { data: response .data diff --git a/crates/bitwarden/src/secrets_manager/secrets/sync.rs b/crates/bitwarden-sm/src/secrets/sync.rs similarity index 86% rename from crates/bitwarden/src/secrets_manager/secrets/sync.rs rename to crates/bitwarden-sm/src/secrets/sync.rs index 804daa5bf..9c922a002 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/sync.rs +++ b/crates/bitwarden-sm/src/secrets/sync.rs @@ -1,12 +1,11 @@ use bitwarden_api_api::models::SecretsSyncResponseModel; -use bitwarden_core::require; +use bitwarden_core::{client::encryption_settings::EncryptionSettings, require, Client, Error}; use chrono::{DateTime, Utc}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{client::encryption_settings::EncryptionSettings, error::Result, Client}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -20,8 +19,8 @@ pub struct SecretsSyncRequest { pub(crate) async fn sync_secrets( client: &Client, input: &SecretsSyncRequest, -) -> Result { - let config = client.get_api_configurations().await; +) -> Result { + 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( @@ -31,7 +30,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) } @@ -47,7 +46,7 @@ impl SecretsSyncResponse { pub(crate) fn process_response( response: SecretsSyncResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let has_changes = require!(response.has_changes); if has_changes { diff --git a/crates/bitwarden/src/secrets_manager/secrets/update.rs b/crates/bitwarden-sm/src/secrets/update.rs similarity index 85% rename from crates/bitwarden/src/secrets_manager/secrets/update.rs rename to crates/bitwarden-sm/src/secrets/update.rs index 8d29927e8..00f1ed2a4 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/update.rs +++ b/crates/bitwarden-sm/src/secrets/update.rs @@ -1,12 +1,11 @@ use bitwarden_api_api::models::SecretUpdateRequestModel; -use bitwarden_core::VaultLocked; +use bitwarden_core::{client::Client, Error, VaultLocked}; use bitwarden_crypto::KeyEncryptable; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; use super::SecretResponse; -use crate::{client::Client, error::Result}; #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -25,8 +24,9 @@ pub struct SecretPutRequest { pub(crate) async fn update_secret( client: &Client, input: &SecretPutRequest, -) -> Result { - let enc = client.get_encryption_settings()?; +) -> Result { + let enc = client.internal.get_encryption_settings()?; + let key = enc .get_key(&Some(input.organization_id)) .ok_or(VaultLocked)?; @@ -38,7 +38,7 @@ 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?; 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/crates/bitwarden-uniffi/src/docs.rs b/crates/bitwarden-uniffi/src/docs.rs index 0569bbcb2..5edbc7144 100644 --- a/crates/bitwarden-uniffi/src/docs.rs +++ b/crates/bitwarden-uniffi/src/docs.rs @@ -1,9 +1,10 @@ use bitwarden::{ auth::password::MasterPasswordPolicyOptions, + exporters::ExportFormat, generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest}, mobile::crypto::{InitOrgCryptoRequest, InitUserCryptoRequest}, platform::FingerprintRequest, - tool::{ExportFormat, Send, SendListView, SendView}, + send::{Send, SendListView, SendView}, 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..5a1dfe43a 100644 --- a/crates/bitwarden-uniffi/src/error.rs +++ b/crates/bitwarden-uniffi/src/error.rs @@ -8,6 +8,12 @@ pub enum BitwardenError { E(bitwarden::error::Error), } +impl From for BitwardenError { + fn from(e: bitwarden::Error) -> Self { + Self::E(e.into()) + } +} + impl From for BitwardenError { fn from(e: bitwarden::error::Error) -> Self { Self::E(e) diff --git a/crates/bitwarden-uniffi/src/platform/fido2.rs b/crates/bitwarden-uniffi/src/platform/fido2.rs index 7cc45a2cb..e5245faef 100644 --- a/crates/bitwarden-uniffi/src/platform/fido2.rs +++ b/crates/bitwarden-uniffi/src/platform/fido2.rs @@ -2,16 +2,16 @@ use std::sync::Arc; use bitwarden::{ error::Error, - platform::fido2::{ - CheckUserOptions, ClientData, Fido2CallbackError as BitFido2CallbackError, - Fido2CredentialAutofillView, GetAssertionRequest, GetAssertionResult, - MakeCredentialRequest, MakeCredentialResult, + fido::{ + CheckUserOptions, ClientData, ClientFido2Ext, Fido2CallbackError as BitFido2CallbackError, + GetAssertionRequest, GetAssertionResult, MakeCredentialRequest, MakeCredentialResult, PublicKeyCredentialAuthenticatorAssertionResponse, PublicKeyCredentialAuthenticatorAttestationResponse, PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, }, vault::{Cipher, CipherView, Fido2CredentialNewView}, }; +use bitwarden_fido::Fido2CredentialAutofillView; use crate::{error::Result, Client}; @@ -51,7 +51,6 @@ impl ClientFido2 { let result = self .0 .0 - .platform() .fido2() .decrypt_fido2_autofill_credentials(cipher_view) .map_err(Error::DecryptFido2AutofillCredentialsError)?; @@ -73,8 +72,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); @@ -87,8 +85,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); @@ -104,8 +101,8 @@ 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); @@ -118,8 +115,7 @@ impl ClientFido2Authenticator { } pub async fn credentials_for_autofill(&self) -> 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); @@ -143,8 +139,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); @@ -162,8 +157,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); @@ -258,9 +252,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>>, @@ -298,9 +290,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()) @@ -325,16 +317,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/platform/mod.rs b/crates/bitwarden-uniffi/src/platform/mod.rs index fe7c401ee..63ff6e183 100644 --- a/crates/bitwarden-uniffi/src/platform/mod.rs +++ b/crates/bitwarden-uniffi/src/platform/mod.rs @@ -27,7 +27,7 @@ impl ClientPlatform { /// Load feature flags into the client pub fn load_flags(&self, flags: std::collections::HashMap) -> Result<()> { - self.0 .0.load_flags(flags); + self.0 .0.internal.load_flags(flags); Ok(()) } diff --git a/crates/bitwarden-uniffi/src/tool/mod.rs b/crates/bitwarden-uniffi/src/tool/mod.rs index a590b41a3..1fd439a4f 100644 --- a/crates/bitwarden-uniffi/src/tool/mod.rs +++ b/crates/bitwarden-uniffi/src/tool/mod.rs @@ -1,8 +1,12 @@ use std::sync::Arc; use bitwarden::{ - generators::{PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest}, - tool::ExportFormat, + error::Error, + exporters::{ClientExportersExt, ExportFormat}, + generators::{ + ClientGeneratorExt, PassphraseGeneratorRequest, PasswordGeneratorRequest, + UsernameGeneratorRequest, + }, vault::{Cipher, Collection, Folder}, }; @@ -18,17 +22,33 @@ pub struct ClientGenerators(pub(crate) Arc); impl ClientGenerators { /// **API Draft:** Generate Password pub fn password(&self, settings: PasswordGeneratorRequest) -> Result { - Ok(self.0 .0.generator().password(settings)?) + Ok(self + .0 + .0 + .generator() + .password(settings) + .map_err(Error::PasswordError)?) } /// **API Draft:** Generate Passphrase pub fn passphrase(&self, settings: PassphraseGeneratorRequest) -> Result { - Ok(self.0 .0.generator().passphrase(settings)?) + Ok(self + .0 + .0 + .generator() + .passphrase(settings) + .map_err(Error::PassphraseError)?) } /// **API Draft:** Generate Username pub async fn username(&self, settings: UsernameGeneratorRequest) -> Result { - Ok(self.0 .0.generator().username(settings).await?) + Ok(self + .0 + .0 + .generator() + .username(settings) + .await + .map_err(Error::UsernameError)?) } } @@ -48,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 @@ -62,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/tool/sends.rs b/crates/bitwarden-uniffi/src/tool/sends.rs index ac9482429..1d5a056a3 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-uniffi/src/vault/attachments.rs b/crates/bitwarden-uniffi/src/vault/attachments.rs index 0084029d2..e8bddd124 100644 --- a/crates/bitwarden-uniffi/src/vault/attachments.rs +++ b/crates/bitwarden-uniffi/src/vault/attachments.rs @@ -1,6 +1,8 @@ use std::{path::Path, sync::Arc}; -use bitwarden::vault::{Attachment, AttachmentEncryptResult, AttachmentView, Cipher}; +use bitwarden::vault::{ + Attachment, AttachmentEncryptResult, AttachmentView, Cipher, ClientVaultExt, +}; use crate::{Client, Result}; diff --git a/crates/bitwarden-uniffi/src/vault/ciphers.rs b/crates/bitwarden-uniffi/src/vault/ciphers.rs index 06ddd1df5..1195cf81a 100644 --- a/crates/bitwarden-uniffi/src/vault/ciphers.rs +++ b/crates/bitwarden-uniffi/src/vault/ciphers.rs @@ -1,6 +1,9 @@ use std::sync::Arc; -use bitwarden::vault::{Cipher, CipherListView, CipherView}; +use bitwarden::{ + error::Error, + vault::{Cipher, CipherListView, CipherView, ClientVaultExt}, +}; use bitwarden_vault::Fido2CredentialView; use uuid::Uuid; @@ -49,6 +52,7 @@ impl ClientCiphers { .0 .vault() .ciphers() - .move_to_organization(cipher, organization_id)?) + .move_to_organization(cipher, organization_id) + .map_err(Error::Cipher)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/collections.rs b/crates/bitwarden-uniffi/src/vault/collections.rs index 47f84426b..84d928e64 100644 --- a/crates/bitwarden-uniffi/src/vault/collections.rs +++ b/crates/bitwarden-uniffi/src/vault/collections.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bitwarden::vault::{Collection, CollectionView}; +use bitwarden::vault::{ClientVaultExt, Collection, CollectionView}; use crate::{Client, Result}; diff --git a/crates/bitwarden-uniffi/src/vault/folders.rs b/crates/bitwarden-uniffi/src/vault/folders.rs index 3fa5935b5..2efeb1f11 100644 --- a/crates/bitwarden-uniffi/src/vault/folders.rs +++ b/crates/bitwarden-uniffi/src/vault/folders.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bitwarden::vault::{Folder, FolderView}; +use bitwarden::vault::{ClientVaultExt, Folder, FolderView}; use crate::{Client, Result}; diff --git a/crates/bitwarden-uniffi/src/vault/mod.rs b/crates/bitwarden-uniffi/src/vault/mod.rs index 5259bc2bd..5f4e80707 100644 --- a/crates/bitwarden-uniffi/src/vault/mod.rs +++ b/crates/bitwarden-uniffi/src/vault/mod.rs @@ -1,6 +1,9 @@ use std::sync::Arc; -use bitwarden::vault::TotpResponse; +use bitwarden::{ + error::Error, + vault::{ClientVaultExt, TotpResponse}, +}; use chrono::{DateTime, Utc}; use crate::{error::Result, Client}; @@ -48,6 +51,11 @@ impl ClientVault { /// - OTP Auth URI /// - Steam URI pub fn generate_totp(&self, key: String, time: Option>) -> Result { - Ok(self.0 .0.vault().generate_totp(key, time)?) + Ok(self + .0 + .0 + .vault() + .generate_totp(key, time) + .map_err(Error::Totp)?) } } diff --git a/crates/bitwarden-uniffi/src/vault/password_history.rs b/crates/bitwarden-uniffi/src/vault/password_history.rs index 12ef993be..3fa0fd3bc 100644 --- a/crates/bitwarden-uniffi/src/vault/password_history.rs +++ b/crates/bitwarden-uniffi/src/vault/password_history.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bitwarden::vault::{PasswordHistory, PasswordHistoryView}; +use bitwarden::vault::{ClientVaultExt, PasswordHistory, PasswordHistoryView}; use crate::{Client, Result}; diff --git a/crates/bitwarden-vault/Cargo.toml b/crates/bitwarden-vault/Cargo.toml index 71fd2a5b7..e875e4c06 100644 --- a/crates/bitwarden-vault/Cargo.toml +++ b/crates/bitwarden-vault/Cargo.toml @@ -21,9 +21,9 @@ 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-core = { workspace = true, features = ["internal"] } bitwarden-crypto = { workspace = true } chrono = { version = ">=0.4.26, <0.5", features = [ "clock", @@ -42,5 +42,8 @@ thiserror = ">=1.0.40, <2.0" uniffi = { version = "=0.27.2", optional = true } uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } +[dev-dependencies] +tokio = { version = "1.36.0", features = ["rt", "macros"] } + [lints] workspace = true diff --git a/crates/bitwarden-vault/src/cipher/cipher.rs b/crates/bitwarden-vault/src/cipher/cipher.rs index 730b80339..c1e84638c 100644 --- a/crates/bitwarden-vault/src/cipher/cipher.rs +++ b/crates/bitwarden-vault/src/cipher/cipher.rs @@ -14,9 +14,12 @@ use uuid::Uuid; use super::{ attachment, card, field, identity, local_data::{LocalData, LocalDataView}, - login, secure_note, + secure_note, +}; +use crate::{ + password_history, Fido2CredentialFullView, Fido2CredentialView, Login, LoginView, + VaultParseError, }; -use crate::{password_history, Fido2CredentialFullView, Fido2CredentialView, VaultParseError}; #[derive(Debug, Error)] pub enum CipherError { @@ -65,7 +68,7 @@ pub struct Cipher { pub notes: Option, pub r#type: CipherType, - pub login: Option, + pub login: Option, pub identity: Option, pub card: Option, pub secure_note: Option, @@ -101,7 +104,7 @@ pub struct CipherView { pub notes: Option, pub r#type: CipherType, - pub login: Option, + pub login: Option, pub identity: Option, pub card: Option, pub secure_note: Option, @@ -606,14 +609,14 @@ mod tests { use std::collections::HashMap; use attachment::AttachmentView; - use login::Fido2Credential; use super::*; + use crate::Fido2Credential; fn generate_cipher() -> CipherView { CipherView { r#type: CipherType::Login, - login: Some(login::LoginView { + login: Some(LoginView { username: Some("test_username".to_string()), password: Some("test_password".to_string()), password_revision_date: None, diff --git a/crates/bitwarden/src/mobile/vault/client_totp.rs b/crates/bitwarden-vault/src/client_totp.rs similarity index 66% rename from crates/bitwarden/src/mobile/vault/client_totp.rs rename to crates/bitwarden-vault/src/client_totp.rs index b1e7747b3..da1329125 100644 --- a/crates/bitwarden/src/mobile/vault/client_totp.rs +++ b/crates/bitwarden-vault/src/client_totp.rs @@ -1,7 +1,6 @@ -use bitwarden_vault::{generate_totp, TotpResponse}; use chrono::{DateTime, Utc}; -use crate::{error::Result, vault::ClientVault}; +use crate::{generate_totp, ClientVault, TotpError, TotpResponse}; impl<'a> ClientVault<'a> { /// Generate a TOTP code from a provided key. @@ -14,7 +13,7 @@ impl<'a> ClientVault<'a> { &'a self, key: String, time: Option>, - ) -> Result { - Ok(generate_totp(key, time)?) + ) -> Result { + generate_totp(key, time) } } diff --git a/crates/bitwarden-vault/src/client_vault.rs b/crates/bitwarden-vault/src/client_vault.rs new file mode 100644 index 000000000..67f6792b9 --- /dev/null +++ b/crates/bitwarden-vault/src/client_vault.rs @@ -0,0 +1,30 @@ +use bitwarden_core::Client; + +use crate::{ + sync::{sync, SyncError}, + SyncRequest, SyncResponse, +}; + +pub struct ClientVault<'a> { + pub(crate) client: &'a Client, +} + +impl<'a> ClientVault<'a> { + pub fn new(client: &'a Client) -> Self { + Self { client } + } + + pub async fn sync(&self, input: &SyncRequest) -> Result { + sync(self.client, input).await + } +} + +pub trait ClientVaultExt<'a> { + fn vault(&'a self) -> ClientVault<'a>; +} + +impl<'a> ClientVaultExt<'a> for Client { + fn vault(&'a self) -> ClientVault<'a> { + ClientVault::new(self) + } +} diff --git a/crates/bitwarden-vault/src/lib.rs b/crates/bitwarden-vault/src/lib.rs index 1e5b5c5aa..8a65f021d 100644 --- a/crates/bitwarden-vault/src/lib.rs +++ b/crates/bitwarden-vault/src/lib.rs @@ -17,3 +17,9 @@ mod totp; pub use totp::{generate_totp, TotpError, TotpResponse}; mod error; pub use error::VaultParseError; +mod client_vault; +pub use client_vault::{ClientVault, ClientVaultExt}; +mod client_totp; +mod mobile; +mod sync; +pub use sync::{SyncRequest, SyncResponse}; diff --git a/crates/bitwarden/src/mobile/vault/client_attachments.rs b/crates/bitwarden-vault/src/mobile/client_attachments.rs similarity index 83% rename from crates/bitwarden/src/mobile/vault/client_attachments.rs rename to crates/bitwarden-vault/src/mobile/client_attachments.rs index 4140a4d88..f382075ec 100644 --- a/crates/bitwarden/src/mobile/vault/client_attachments.rs +++ b/crates/bitwarden-vault/src/mobile/client_attachments.rs @@ -1,15 +1,11 @@ use std::path::Path; -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::{EncString, KeyDecryptable, KeyEncryptable, LocateKey}; -use bitwarden_vault::{ - Attachment, AttachmentEncryptResult, AttachmentFile, AttachmentFileView, AttachmentView, Cipher, -}; use crate::{ - error::{Error, Result}, - vault::ClientVault, - Client, + Attachment, AttachmentEncryptResult, AttachmentFile, AttachmentFileView, AttachmentView, + Cipher, ClientVault, }; pub struct ClientAttachments<'a> { @@ -22,8 +18,8 @@ impl<'a> ClientAttachments<'a> { cipher: Cipher, attachment: AttachmentView, buffer: &[u8], - ) -> Result { - let enc = self.client.get_encryption_settings()?; + ) -> Result { + let enc = self.client.internal.get_encryption_settings()?; let key = cipher.locate_key(&enc, &None).ok_or(VaultLocked)?; Ok(AttachmentFileView { @@ -39,7 +35,7 @@ impl<'a> ClientAttachments<'a> { attachment: AttachmentView, decrypted_file_path: &Path, encrypted_file_path: &Path, - ) -> Result { + ) -> Result { let data = std::fs::read(decrypted_file_path)?; let AttachmentEncryptResult { attachment, @@ -54,8 +50,8 @@ impl<'a> ClientAttachments<'a> { cipher: Cipher, attachment: Attachment, encrypted_buffer: &[u8], - ) -> Result> { - let enc = self.client.get_encryption_settings()?; + ) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; let key = cipher.locate_key(&enc, &None).ok_or(VaultLocked)?; AttachmentFile { @@ -72,7 +68,7 @@ impl<'a> ClientAttachments<'a> { attachment: Attachment, encrypted_file_path: &Path, decrypted_file_path: &Path, - ) -> Result<()> { + ) -> Result<(), Error> { let data = std::fs::read(encrypted_file_path)?; let decrypted = self.decrypt_buffer(cipher, attachment, &data)?; std::fs::write(decrypted_file_path, decrypted)?; diff --git a/crates/bitwarden/src/mobile/vault/client_ciphers.rs b/crates/bitwarden-vault/src/mobile/client_ciphers.rs similarity index 89% rename from crates/bitwarden/src/mobile/vault/client_ciphers.rs rename to crates/bitwarden-vault/src/mobile/client_ciphers.rs index 2bf612b56..864af8b94 100644 --- a/crates/bitwarden/src/mobile/vault/client_ciphers.rs +++ b/crates/bitwarden-vault/src/mobile/client_ciphers.rs @@ -1,21 +1,26 @@ -use bitwarden_core::VaultLocked; +use bitwarden_core::{Client, Error, VaultLocked}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable, LocateKey}; -use bitwarden_vault::{Cipher, CipherListView, CipherView}; use uuid::Uuid; -use crate::{error::Result, vault::ClientVault, Client}; +use crate::{Cipher, CipherError, CipherListView, CipherView, ClientVault}; pub struct ClientCiphers<'a> { pub(crate) client: &'a Client, } impl<'a> ClientCiphers<'a> { - pub fn encrypt(&self, mut cipher_view: CipherView) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn encrypt(&self, mut cipher_view: CipherView) -> Result { + 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(VaultLocked)?; cipher_view.generate_cipher_key(key)?; } @@ -26,8 +31,8 @@ impl<'a> ClientCiphers<'a> { Ok(cipher) } - pub fn decrypt(&self, cipher: Cipher) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt(&self, cipher: Cipher) -> Result { + let enc = self.client.internal.get_encryption_settings()?; let key = cipher .locate_key(&enc, &None) .ok_or(CryptoError::MissingKey)?; @@ -37,12 +42,12 @@ impl<'a> ClientCiphers<'a> { Ok(cipher_view) } - pub fn decrypt_list(&self, ciphers: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_list(&self, ciphers: Vec) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; - let cipher_views: Result> = ciphers + let cipher_views: Result, _> = ciphers .iter() - .map(|c| -> Result { + .map(|c| -> Result { let key = c.locate_key(&enc, &None).ok_or(CryptoError::MissingKey)?; Ok(c.decrypt_with_key(key)?) }) @@ -55,10 +60,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) } @@ -67,8 +74,8 @@ impl<'a> ClientCiphers<'a> { &self, mut cipher_view: CipherView, organization_id: Uuid, - ) -> Result { - let enc = self.client.get_encryption_settings()?; + ) -> Result { + let enc = self.client.internal.get_encryption_settings()?; cipher_view.move_to_organization(&enc, organization_id)?; Ok(cipher_view) } @@ -85,10 +92,10 @@ impl<'a> ClientVault<'a> { #[cfg(test)] mod tests { - use bitwarden_vault::{Attachment, CipherRepromptType, CipherType, Login}; + use bitwarden_core::client::test_accounts::test_bitwarden_com_account; use super::*; - use crate::client::test_accounts::test_bitwarden_com_account; + use crate::{Attachment, CipherRepromptType, CipherType, ClientVaultExt, Login}; #[tokio::test] async fn test_decrypt_list() { diff --git a/crates/bitwarden/src/mobile/vault/client_collection.rs b/crates/bitwarden-vault/src/mobile/client_collection.rs similarity index 81% rename from crates/bitwarden/src/mobile/vault/client_collection.rs rename to crates/bitwarden-vault/src/mobile/client_collection.rs index 09f1f3c6a..42cda4bc5 100644 --- a/crates/bitwarden/src/mobile/vault/client_collection.rs +++ b/crates/bitwarden-vault/src/mobile/client_collection.rs @@ -1,15 +1,15 @@ +use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, LocateKey}; -use bitwarden_vault::{Collection, CollectionView}; -use crate::{error::Result, vault::ClientVault, Client}; +use crate::{ClientVault, Collection, CollectionView}; pub struct ClientCollections<'a> { pub(crate) client: &'a Client, } impl<'a> ClientCollections<'a> { - pub fn decrypt(&self, collection: Collection) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt(&self, collection: Collection) -> Result { + let enc = self.client.internal.get_encryption_settings()?; let key = collection .locate_key(&enc, &None) .ok_or(CryptoError::MissingKey)?; @@ -19,12 +19,12 @@ impl<'a> ClientCollections<'a> { Ok(view) } - pub fn decrypt_list(&self, collections: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_list(&self, collections: Vec) -> Result, Error> { + let enc = self.client.internal.get_encryption_settings()?; - let views: Result> = collections + let views: Result, _> = collections .iter() - .map(|c| -> Result { + .map(|c| -> Result { let key = c.locate_key(&enc, &None).ok_or(CryptoError::MissingKey)?; Ok(c.decrypt_with_key(key)?) }) @@ -44,9 +44,10 @@ impl<'a> ClientVault<'a> { #[cfg(test)] mod tests { - use bitwarden_vault::Collection; + use bitwarden_core::client::test_accounts::test_bitwarden_com_account; - use crate::{client::test_accounts::test_bitwarden_com_account, Client}; + use super::*; + use crate::ClientVaultExt; #[tokio::test] async fn test_decrypt_list() { diff --git a/crates/bitwarden/src/mobile/vault/client_folders.rs b/crates/bitwarden-vault/src/mobile/client_folders.rs similarity index 69% rename from crates/bitwarden/src/mobile/vault/client_folders.rs rename to crates/bitwarden-vault/src/mobile/client_folders.rs index 668125da2..93d89c4d6 100644 --- a/crates/bitwarden/src/mobile/vault/client_folders.rs +++ b/crates/bitwarden-vault/src/mobile/client_folders.rs @@ -1,15 +1,15 @@ +use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable}; -use bitwarden_vault::{Folder, FolderView}; -use crate::{error::Result, vault::ClientVault, Client}; +use crate::{ClientVault, Folder, FolderView}; pub struct ClientFolders<'a> { pub(crate) client: &'a Client, } impl<'a> ClientFolders<'a> { - pub fn encrypt(&self, folder_view: FolderView) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn encrypt(&self, folder_view: FolderView) -> Result { + 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)?; @@ -17,8 +17,8 @@ impl<'a> ClientFolders<'a> { Ok(folder) } - pub fn decrypt(&self, folder: Folder) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt(&self, folder: Folder) -> Result { + 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)?; @@ -26,8 +26,8 @@ impl<'a> ClientFolders<'a> { Ok(folder_view) } - pub fn decrypt_list(&self, folders: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_list(&self, folders: Vec) -> Result, Error> { + 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/src/mobile/vault/client_password_history.rs b/crates/bitwarden-vault/src/mobile/client_password_history.rs similarity index 65% rename from crates/bitwarden/src/mobile/vault/client_password_history.rs rename to crates/bitwarden-vault/src/mobile/client_password_history.rs index db0f5fa53..8af07a120 100644 --- a/crates/bitwarden/src/mobile/vault/client_password_history.rs +++ b/crates/bitwarden-vault/src/mobile/client_password_history.rs @@ -1,15 +1,15 @@ +use bitwarden_core::{Client, Error}; use bitwarden_crypto::{CryptoError, KeyDecryptable, KeyEncryptable}; -use bitwarden_vault::{PasswordHistory, PasswordHistoryView}; -use crate::{error::Result, vault::ClientVault, Client}; +use crate::{ClientVault, PasswordHistory, PasswordHistoryView}; pub struct ClientPasswordHistory<'a> { pub(crate) client: &'a Client, } impl<'a> ClientPasswordHistory<'a> { - pub fn encrypt(&self, history_view: PasswordHistoryView) -> Result { - let enc = self.client.get_encryption_settings()?; + pub fn encrypt(&self, history_view: PasswordHistoryView) -> Result { + 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)?; @@ -17,8 +17,11 @@ impl<'a> ClientPasswordHistory<'a> { Ok(history) } - pub fn decrypt_list(&self, history: Vec) -> Result> { - let enc = self.client.get_encryption_settings()?; + pub fn decrypt_list( + &self, + history: Vec, + ) -> Result, Error> { + 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-vault/src/mobile/mod.rs b/crates/bitwarden-vault/src/mobile/mod.rs new file mode 100644 index 000000000..59e28b6e8 --- /dev/null +++ b/crates/bitwarden-vault/src/mobile/mod.rs @@ -0,0 +1,5 @@ +mod client_attachments; +mod client_ciphers; +mod client_collection; +mod client_folders; +mod client_password_history; diff --git a/crates/bitwarden/src/vault/sync.rs b/crates/bitwarden-vault/src/sync.rs similarity index 76% rename from crates/bitwarden/src/vault/sync.rs rename to crates/bitwarden-vault/src/sync.rs index d751dbf6f..6b4845d35 100644 --- a/crates/bitwarden/src/vault/sync.rs +++ b/crates/bitwarden-vault/src/sync.rs @@ -1,17 +1,27 @@ use bitwarden_api_api::models::{ DomainsResponseModel, ProfileOrganizationResponseModel, ProfileResponseModel, SyncResponseModel, }; -use bitwarden_core::require; -use bitwarden_vault::{Cipher, Collection, Folder, GlobalDomains}; +use bitwarden_core::{ + client::encryption_settings::EncryptionSettings, require, Client, Error, MissingFieldError, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use thiserror::Error; use uuid::Uuid; -use crate::{ - admin_console::Policy, - client::{encryption_settings::EncryptionSettings, Client}, - error::{Error, Result}, -}; +use crate::{Cipher, Collection, Folder, GlobalDomains, VaultParseError}; + +#[derive(Debug, Error)] +pub enum SyncError { + #[error(transparent)] + Core(#[from] bitwarden_core::Error), + + #[error(transparent)] + MissingFieldError(#[from] MissingFieldError), + + #[error(transparent)] + VaultParse(#[from] VaultParseError), +} #[derive(Serialize, Deserialize, Debug, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -20,10 +30,11 @@ pub struct SyncRequest { pub exclude_subdomains: Option, } -pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result { - let config = client.get_api_configurations().await; - let sync = - bitwarden_api_api::apis::sync_api::sync_get(&config.api, input.exclude_subdomains).await?; +pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result { + 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()))?; let org_keys: Vec<_> = require!(sync.profile.as_ref()) .organizations @@ -33,7 +44,7 @@ pub(crate) async fn sync(client: &Client, input: &SyncRequest) -> Result, pub domains: Option, - pub policies: Vec, - pub sends: Vec, + //pub policies: Vec, + //pub sends: Vec, } impl SyncResponse { pub(crate) fn process_response( response: SyncResponseModel, enc: &EncryptionSettings, - ) -> Result { + ) -> Result { let profile = require!(response.profile); let ciphers = require!(response.ciphers); @@ -101,8 +112,8 @@ impl SyncResponse { 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))?, + //policies: try_into_iter(require!(response.policies))?, + //sends: try_into_iter(require!(response.sends))?, }) } } @@ -110,7 +121,7 @@ impl SyncResponse { impl ProfileOrganizationResponse { fn process_response( response: ProfileOrganizationResponseModel, - ) -> Result { + ) -> Result { Ok(ProfileOrganizationResponse { id: require!(response.id), }) @@ -121,7 +132,7 @@ impl ProfileResponse { fn process_response( response: ProfileResponseModel, _enc: &EncryptionSettings, - ) -> Result { + ) -> Result { Ok(ProfileResponse { id: require!(response.id), name: require!(response.name), @@ -139,7 +150,7 @@ impl ProfileResponse { } impl TryFrom for DomainResponse { - type Error = Error; + type Error = SyncError; fn try_from(value: DomainsResponseModel) -> Result { Ok(Self { @@ -148,8 +159,8 @@ impl TryFrom for DomainResponse { .global_equivalent_domains .unwrap_or_default() .into_iter() - .map(|s| s.try_into().map_err(Error::VaultParse)) - .collect::>>()?, + .map(|s| s.try_into()) + .collect::, _>>()?, }) } } 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 diff --git a/crates/bitwarden/Cargo.toml b/crates/bitwarden/Cargo.toml index 783d5676d..3bd1f02fa 100644 --- a/crates/bitwarden/Cargo.toml +++ b/crates/bitwarden/Cargo.toml @@ -17,29 +17,27 @@ license-file.workspace = true default = ["secrets"] internal = [ + "bitwarden-core/internal", "dep:bitwarden-exporters", "dep:bitwarden-generators", "dep:bitwarden-send", "dep:bitwarden-vault", ] # Internal testing methods no-memory-hardening = [ - "bitwarden-crypto/no-memory-hardening", + "bitwarden-core/no-memory-hardening", ] # Disable memory hardening features uniffi = [ "bitwarden-core/uniffi", "bitwarden-crypto/uniffi", + "bitwarden-exporters/uniffi", + "bitwarden-fido/uniffi", "bitwarden-generators/uniffi", "bitwarden-send/uniffi", "bitwarden-vault/uniffi", - "bitwarden-fido/uniffi", - "dep:uniffi", ] # Uniffi bindings -secrets = [] # Secrets manager API -wasm-bindgen = ["chrono/wasmbind"] +secrets = ["bitwarden-core/secrets", "dep:bitwarden-sm"] # Secrets manager API [dependencies] -async-trait = ">=0.1.80, <0.2" -base64 = ">=0.21.2, <0.23" bitwarden-api-api = { workspace = true } bitwarden-api-identity = { workspace = true } bitwarden-core = { workspace = true } @@ -48,58 +46,12 @@ bitwarden-exporters = { workspace = true, optional = true } bitwarden-fido = { workspace = true, optional = true } bitwarden-generators = { workspace = true, optional = true } bitwarden-send = { workspace = true, optional = true } +bitwarden-sm = { workspace = true, optional = true } bitwarden-vault = { workspace = true, optional = true } -chrono = { version = ">=0.4.26, <0.5", features = [ - "clock", - "serde", - "std", -], default-features = false } -# We don't use this directly (it's used by rand), but we need it here to enable WASM support -getrandom = { version = ">=0.2.9, <0.3", features = ["js"] } -log = ">=0.4.18, <0.5" -rand = ">=0.8.5, <0.9" -reqwest = { version = ">=0.12.5, <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" -serde_qs = ">=0.12.0, <0.14" -serde_repr = ">=0.1.12, <0.2" thiserror = ">=1.0.40, <2.0" -uniffi = { version = "=0.27.2", optional = true, features = ["tokio"] } -uuid = { version = ">=1.3.3, <2.0", features = ["serde"] } -zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } -zxcvbn = ">= 2.2.2, <3.0" - -[target.'cfg(all(not(target_os = "android"), not(target_arch="wasm32")))'.dependencies] -# By default, we use rustls as the TLS stack and rust-platform-verifier to support user-installed root certificates -# There are a few exceptions to this: -# - WASM doesn't require a TLS stack, as it just uses the browsers/node fetch -# - Android uses webpki-roots for the moment -reqwest = { version = ">=0.12.5, <0.13", features = [ - "rustls-tls-manual-roots", -], default-features = false } -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 -# This means that for the moment android won't support self-signed certificates, even if they are included in the OS trust store -reqwest = { version = ">=0.12.5, <0.13", features = [ - "rustls-tls-webpki-roots", -], default-features = false } - -# This is a workaround to fix a bug with version 2.11.0 that added some symbols that are not available on iOS -# The bug is fixed already but the fix is not released yet. https://github.com/kornelski/rust-security-framework/pull/204 -[target.'cfg(target_os = "ios")'.dependencies] -security-framework = { version = "=2.10" } [dev-dependencies] -rand_chacha = "0.3.1" -tokio = { version = "1.36.0", features = ["rt", "macros"] } -wiremock = "0.6.0" -zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } +uuid = { version = ">=1.3.3, <2.0" } [lints] workspace = true 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/client/mod.rs b/crates/bitwarden/src/client/mod.rs deleted file mode 100644 index 1568152e4..000000000 --- a/crates/bitwarden/src/client/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -//! Bitwarden SDK Client - -pub(crate) use client::*; -#[allow(clippy::module_inception)] -mod client; -pub mod client_settings; -pub(crate) mod encryption_settings; - -#[cfg(feature = "internal")] -mod flags; - -pub use client::Client; -pub use client_settings::{ClientSettings, DeviceType}; - -#[cfg(feature = "internal")] -#[cfg(test)] -pub(crate) mod test_accounts; diff --git a/crates/bitwarden/src/error.rs b/crates/bitwarden/src/error.rs index 46f34404f..06ef09648 100644 --- a/crates/bitwarden/src/error.rs +++ b/crates/bitwarden/src/error.rs @@ -2,56 +2,16 @@ 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 = "internal")] use bitwarden_generators::{PassphraseError, PasswordError, UsernameError}; -use reqwest::StatusCode; use thiserror::Error; #[derive(Debug, Error)] pub enum 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("Access token is not in a valid format: {0}")] - AccessTokenInvalid(#[from] AccessTokenInvalidError), - - #[error("The response received was invalid and could not be processed")] - InvalidResponse, - - #[error("Cryptography error, {0}")] - Crypto(#[from] bitwarden_crypto::CryptoError), - - #[error("Error parsing Identity response: {0}")] - IdentityFail(crate::auth::api::response::IdentityTokenFailResponse), - - #[error(transparent)] - Reqwest(#[from] reqwest::Error), - #[error(transparent)] - Serde(#[from] serde_json::Error), - #[error(transparent)] - Io(#[from] std::io::Error), - #[error(transparent)] - InvalidBase64(#[from] base64::DecodeError), - #[error(transparent)] - Chrono(#[from] chrono::ParseError), - - #[error("Received error message from server: [{}] {}", .status, .message)] - ResponseContent { status: StatusCode, message: String }, - - #[error("The state file version is invalid")] - InvalidStateFileVersion, - - #[error("The state file could not be read")] - InvalidStateFile, + Core(#[from] bitwarden_core::Error), // Generators #[cfg(feature = "internal")] @@ -64,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")] @@ -100,18 +52,11 @@ pub enum Error { #[cfg(all(feature = "uniffi", feature = "internal"))] #[error(transparent)] DecryptFido2AutofillCredentialsError( - #[from] crate::platform::fido2::DecryptFido2AutofillCredentialsError, + #[from] bitwarden_fido::DecryptFido2AutofillCredentialsError, ), #[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>), @@ -129,24 +74,6 @@ impl From<&'static str> for Error { } } -#[derive(Debug, Error)] -pub enum AccessTokenInvalidError { - #[error("Doesn't contain a decryption key")] - NoKey, - #[error("Has the wrong number of parts")] - WrongParts, - #[error("Is the wrong version")] - WrongVersion, - #[error("Has an invalid identifier")] - InvalidUuid, - - #[error("Error decoding base64: {0}")] - InvalidBase64(#[from] base64::DecodeError), - - #[error("Invalid base64 length: expected {expected}, got {got}")] - InvalidBase64Length { expected: usize, got: usize }, -} - // Ensure that the error messages implement Send and Sync #[cfg(test)] const _: () = { @@ -158,24 +85,4 @@ const _: () = { } }; -macro_rules! impl_bitwarden_error { - ($name:ident) => { - impl From<$name> for Error { - fn from(e: $name) -> Self { - match e { - $name::Reqwest(e) => Self::Reqwest(e), - $name::ResponseError(e) => Self::ResponseContent { - status: e.status, - message: e.content, - }, - $name::Serde(e) => Self::Serde(e), - $name::Io(e) => Self::Io(e), - } - } - } - }; -} -impl_bitwarden_error!(ApiError); -impl_bitwarden_error!(IdentityError); - pub type Result = std::result::Result; diff --git a/crates/bitwarden/src/lib.rs b/crates/bitwarden/src/lib.rs index b5506485f..40168761c 100644 --- a/crates/bitwarden/src/lib.rs +++ b/crates/bitwarden/src/lib.rs @@ -16,8 +16,10 @@ //! //! ```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; //! @@ -56,35 +58,36 @@ #[doc = include_str!("../README.md")] mod readme {} -#[cfg(feature = "uniffi")] -uniffi::setup_scaffolding!(); - -#[cfg(feature = "internal")] -pub mod admin_console; -pub mod auth; -pub mod client; +pub use bitwarden_core::*; pub mod error; + #[cfg(feature = "internal")] -pub mod mobile; -#[cfg(feature = "internal")] -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; -#[cfg(feature = "internal")] -pub mod vault; +pub mod internal { + pub mod generators { + pub use bitwarden_generators::*; + } -pub use client::{Client, ClientSettings, DeviceType}; + pub mod exporters { + pub use bitwarden_exporters::*; + } -#[cfg(feature = "internal")] -pub mod generators { - pub use bitwarden_generators::{ - PassphraseGeneratorRequest, PasswordGeneratorRequest, UsernameGeneratorRequest, - }; + pub mod send { + pub use bitwarden_send::*; + } + + pub mod vault { + pub use bitwarden_vault::*; + } + + #[cfg(feature = "uniffi")] + pub mod fido { + pub use bitwarden_fido::*; + } } +#[cfg(feature = "internal")] +pub use internal::*; -pub use bitwarden_crypto::ZeroizingAllocator; +#[cfg(feature = "secrets")] +pub mod secrets_manager { + pub use bitwarden_sm::*; +} diff --git a/crates/bitwarden/src/mobile/tool/mod.rs b/crates/bitwarden/src/mobile/tool/mod.rs deleted file mode 100644 index 729697715..000000000 --- a/crates/bitwarden/src/mobile/tool/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod client_sends; -pub use client_sends::ClientSends; diff --git a/crates/bitwarden/src/mobile/vault/mod.rs b/crates/bitwarden/src/mobile/vault/mod.rs deleted file mode 100644 index 18b96eb50..000000000 --- a/crates/bitwarden/src/mobile/vault/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -mod client_attachments; -mod client_ciphers; -mod client_collection; -mod client_folders; -mod client_password_history; -mod client_totp; - -pub use client_attachments::ClientAttachments; -pub use client_ciphers::ClientCiphers; -pub use client_collection::ClientCollections; -pub use client_folders::ClientFolders; -pub use client_password_history::ClientPasswordHistory; diff --git a/crates/bitwarden/src/secrets_manager/client_projects.rs b/crates/bitwarden/src/secrets_manager/client_projects.rs deleted file mode 100644 index 5c8f3657a..000000000 --- a/crates/bitwarden/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 crate::Client, -} - -impl<'a> ClientProjects<'a> { - pub async fn get(&self, input: &ProjectGetRequest) -> Result { - get_project(self.client, input).await - } - - pub async fn create(&self, input: &ProjectCreateRequest) -> Result { - create_project(self.client, input).await - } - - pub async fn list(&self, input: &ProjectsListRequest) -> Result { - list_projects(self.client, input).await - } - - pub async fn update(&self, input: &ProjectPutRequest) -> Result { - update_project(self.client, input).await - } - - pub async fn delete(&self, input: ProjectsDeleteRequest) -> Result { - delete_projects(self.client, input).await - } -} - -impl<'a> Client { - pub fn projects(&'a self) -> ClientProjects<'a> { - ClientProjects { client: self } - } -} diff --git a/crates/bitwarden/src/secrets_manager/client_secrets.rs b/crates/bitwarden/src/secrets_manager/client_secrets.rs deleted file mode 100644 index 1050c95d8..000000000 --- a/crates/bitwarden/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 crate::Client, -} - -impl<'a> ClientSecrets<'a> { - pub async fn get(&self, input: &SecretGetRequest) -> Result { - get_secret(self.client, input).await - } - - pub async fn get_by_ids(&self, input: SecretsGetRequest) -> Result { - get_secrets_by_ids(self.client, input).await - } - - pub async fn create(&self, input: &SecretCreateRequest) -> Result { - create_secret(self.client, input).await - } - - pub async fn list( - &self, - input: &SecretIdentifiersRequest, - ) -> Result { - list_secrets(self.client, input).await - } - - pub async fn list_by_project( - &self, - input: &SecretIdentifiersByProjectRequest, - ) -> Result { - list_secrets_by_project(self.client, input).await - } - - pub async fn update(&self, input: &SecretPutRequest) -> Result { - update_secret(self.client, input).await - } - - pub async fn delete(&self, input: SecretsDeleteRequest) -> Result { - delete_secrets(self.client, input).await - } - - pub async fn sync(&self, input: &SecretsSyncRequest) -> Result { - sync_secrets(self.client, input).await - } -} - -impl<'a> Client { - pub fn secrets(&'a self) -> ClientSecrets<'a> { - ClientSecrets { client: self } - } -} diff --git a/crates/bitwarden/src/secrets_manager/mod.rs b/crates/bitwarden/src/secrets_manager/mod.rs deleted file mode 100644 index 181edf6b6..000000000 --- a/crates/bitwarden/src/secrets_manager/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -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/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/uniffi_support.rs b/crates/bitwarden/src/uniffi_support.rs deleted file mode 100644 index 562393307..000000000 --- a/crates/bitwarden/src/uniffi_support.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::num::NonZeroU32; - -use bitwarden_crypto::{AsymmetricEncString, EncString}; -use uuid::Uuid; - -type DateTime = chrono::DateTime; -uniffi::ffi_converter_forward!(DateTime, bitwarden_core::UniFfiTag, crate::UniFfiTag); -uniffi::ffi_converter_forward!(Uuid, bitwarden_core::UniFfiTag, crate::UniFfiTag); - -uniffi::ffi_converter_forward!(NonZeroU32, bitwarden_crypto::UniFfiTag, crate::UniFfiTag); -uniffi::ffi_converter_forward!(EncString, bitwarden_crypto::UniFfiTag, crate::UniFfiTag); -uniffi::ffi_converter_forward!( - AsymmetricEncString, - bitwarden_crypto::UniFfiTag, - crate::UniFfiTag -); 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 } - } -} diff --git a/crates/bitwarden/src/vault/mod.rs b/crates/bitwarden/src/vault/mod.rs deleted file mode 100644 index 8a6bf77f6..000000000 --- a/crates/bitwarden/src/vault/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod sync; -pub use sync::{SyncRequest, SyncResponse}; -mod client_vault; -pub use bitwarden_vault::{ - Attachment, AttachmentEncryptResult, AttachmentView, Cipher, CipherListView, CipherView, - Collection, CollectionView, Fido2CredentialNewView, Fido2CredentialView, Folder, FolderView, - PasswordHistory, PasswordHistoryView, TotpResponse, -}; -pub use client_vault::ClientVault; diff --git a/crates/bw/src/auth/login.rs b/crates/bw/src/auth/login.rs index 268014118..51fe64a39 100644 --- a/crates/bw/src/auth/login.rs +++ b/crates/bw/src/auth/login.rs @@ -3,7 +3,7 @@ use bitwarden::{ ApiKeyLoginRequest, PasswordLoginRequest, TwoFactorEmailRequest, TwoFactorProvider, TwoFactorRequest, }, - vault::SyncRequest, + vault::{ClientVaultExt, SyncRequest}, Client, }; use bitwarden_cli::text_prompt_when_none; diff --git a/crates/bw/src/main.rs b/crates/bw/src/main.rs index 66f63d280..a9a7eeea2 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/command/project.rs b/crates/bws/src/command/project.rs index 72060fdf4..90024a9f7 100644 --- a/crates/bws/src/command/project.rs +++ b/crates/bws/src/command/project.rs @@ -1,7 +1,10 @@ use bitwarden::{ - secrets_manager::projects::{ - ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsDeleteRequest, - ProjectsListRequest, + secrets_manager::{ + projects::{ + ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsDeleteRequest, + ProjectsListRequest, + }, + ClientProjectsExt, }, Client, }; diff --git a/crates/bws/src/command/secret.rs b/crates/bws/src/command/secret.rs index 30613016d..744ed396d 100644 --- a/crates/bws/src/command/secret.rs +++ b/crates/bws/src/command/secret.rs @@ -1,7 +1,10 @@ use bitwarden::{ - secrets_manager::secrets::{ - SecretCreateRequest, SecretGetRequest, SecretIdentifiersByProjectRequest, - SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, + secrets_manager::{ + secrets::{ + SecretCreateRequest, SecretGetRequest, SecretIdentifiersByProjectRequest, + SecretIdentifiersRequest, SecretPutRequest, SecretsDeleteRequest, SecretsGetRequest, + }, + ClientSecretsExt, }, Client, }; diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index be1ea2bd4..092df2208 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -101,7 +101,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."); 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 From 3a48ef6af4494379858002c00f084b3f10147b5b Mon Sep 17 00:00:00 2001 From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Date: Wed, 26 Jun 2024 10:53:41 -0500 Subject: [PATCH 06/11] [SM-1175] Remove deprecated bws commands (#836) The purpose of this PR is to remove all the deprecated commands from bws. Went with building off the refactor in `sm/sm-1287`. Co-authored-by: Colton Hurst --- crates/bws/src/cli.rs | 82 ------------------- crates/bws/src/command/project.rs | 24 +++++- crates/bws/src/command/secret.rs | 60 +++++++++++++- crates/bws/src/main.rs | 126 +----------------------------- 4 files changed, 86 insertions(+), 206 deletions(-) diff --git a/crates/bws/src/cli.rs b/crates/bws/src/cli.rs index 48d2f528e..3c55b3a0e 100644 --- a/crates/bws/src/cli.rs +++ b/crates/bws/src/cli.rs @@ -89,31 +89,6 @@ pub(crate) enum Commands { #[command(subcommand)] cmd: SecretCommand, }, - #[command(long_about = "Create a single item (deprecated)", hide(true))] - Create { - #[command(subcommand)] - cmd: CreateCommand, - }, - #[command(long_about = "Delete one or more items (deprecated)", hide(true))] - Delete { - #[command(subcommand)] - cmd: DeleteCommand, - }, - #[command(long_about = "Edit a single item (deprecated)", hide(true))] - Edit { - #[command(subcommand)] - cmd: EditCommand, - }, - #[command(long_about = "Retrieve a single item (deprecated)", hide(true))] - Get { - #[command(subcommand)] - cmd: GetCommand, - }, - #[command(long_about = "List items (deprecated)", hide(true))] - List { - #[command(subcommand)] - cmd: ListCommand, - }, } #[derive(Subcommand, Debug)] @@ -169,60 +144,3 @@ pub(crate) enum ProjectCommand { }, List, } - -#[derive(Subcommand, Debug)] -pub(crate) enum ListCommand { - Projects, - Secrets { project_id: Option }, -} - -#[derive(Subcommand, Debug)] -pub(crate) enum GetCommand { - Project { project_id: Uuid }, - Secret { secret_id: Uuid }, -} - -#[derive(Subcommand, Debug)] -pub(crate) enum CreateCommand { - Project { - name: String, - }, - Secret { - key: String, - value: String, - - #[arg(long, help = "An optional note to add to the secret")] - note: Option, - - #[arg(long, help = "The ID of the project this secret will be added to")] - project_id: Uuid, - }, -} - -#[derive(Subcommand, Debug)] -pub(crate) enum EditCommand { - #[clap(group = ArgGroup::new("edit_field").required(true).multiple(true))] - Project { - project_id: Uuid, - #[arg(long, group = "edit_field")] - name: String, - }, - #[clap(group = ArgGroup::new("edit_field").required(true).multiple(true))] - Secret { - secret_id: Uuid, - #[arg(long, group = "edit_field")] - key: Option, - #[arg(long, group = "edit_field")] - value: Option, - #[arg(long, group = "edit_field")] - note: Option, - #[arg(long, group = "edit_field")] - project_id: Option, - }, -} - -#[derive(Subcommand, Debug)] -pub(crate) enum DeleteCommand { - Project { project_ids: Vec }, - Secret { secret_ids: Vec }, -} diff --git a/crates/bws/src/command/project.rs b/crates/bws/src/command/project.rs index 90024a9f7..3b521e2cb 100644 --- a/crates/bws/src/command/project.rs +++ b/crates/bws/src/command/project.rs @@ -11,7 +11,29 @@ use bitwarden::{ use color_eyre::eyre::{bail, Result}; use uuid::Uuid; -use crate::render::{serialize_response, OutputSettings}; +use crate::{ + render::{serialize_response, OutputSettings}, + ProjectCommand, +}; + +pub(crate) async fn process_command( + command: ProjectCommand, + client: Client, + organization_id: Uuid, + output_settings: OutputSettings, +) -> Result<()> { + match command { + ProjectCommand::List => list(client, organization_id, output_settings).await, + ProjectCommand::Get { project_id } => get(client, project_id, output_settings).await, + ProjectCommand::Create { name } => { + create(client, organization_id, name, output_settings).await + } + ProjectCommand::Edit { project_id, name } => { + edit(client, organization_id, project_id, name, output_settings).await + } + ProjectCommand::Delete { project_ids } => delete(client, project_ids).await, + } +} pub(crate) async fn list( client: Client, diff --git a/crates/bws/src/command/secret.rs b/crates/bws/src/command/secret.rs index 744ed396d..794a1a0b9 100644 --- a/crates/bws/src/command/secret.rs +++ b/crates/bws/src/command/secret.rs @@ -11,7 +11,10 @@ use bitwarden::{ use color_eyre::eyre::{bail, Result}; use uuid::Uuid; -use crate::render::{serialize_response, OutputSettings}; +use crate::{ + render::{serialize_response, OutputSettings}, + SecretCommand, +}; #[derive(Debug)] pub(crate) struct SecretCreateCommandModel { @@ -30,6 +33,61 @@ pub(crate) struct SecretEditCommandModel { pub(crate) project_id: Option, } +pub(crate) async fn process_command( + command: SecretCommand, + client: Client, + organization_id: Uuid, + output_settings: OutputSettings, +) -> Result<()> { + match command { + SecretCommand::List { project_id } => { + list(client, organization_id, project_id, output_settings).await + } + SecretCommand::Get { secret_id } => get(client, secret_id, output_settings).await, + SecretCommand::Create { + key, + value, + note, + project_id, + } => { + create( + client, + organization_id, + SecretCreateCommandModel { + key, + value, + note, + project_id, + }, + output_settings, + ) + .await + } + SecretCommand::Edit { + secret_id, + key, + value, + note, + project_id, + } => { + edit( + client, + organization_id, + SecretEditCommandModel { + id: secret_id, + key, + value, + note, + project_id, + }, + output_settings, + ) + .await + } + SecretCommand::Delete { secret_ids } => delete(client, secret_ids).await, + } +} + pub(crate) async fn list( client: Client, organization_id: Uuid, diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 092df2208..14fc30782 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -7,7 +7,6 @@ use bitwarden::{ use bitwarden_cli::install_color_eyre; use clap::{CommandFactory, Parser}; use color_eyre::eyre::{bail, Result}; -use command::secret::{SecretCreateCommandModel, SecretEditCommandModel}; use log::error; use render::OutputSettings; @@ -113,130 +112,13 @@ async fn process_commands() -> Result<()> { // And finally we process all the commands which require authentication match command { - Commands::Project { - cmd: ProjectCommand::List, + Commands::Project { cmd } => { + command::project::process_command(cmd, client, organization_id, output_settings).await } - | Commands::List { - cmd: ListCommand::Projects, - } => command::project::list(client, organization_id, output_settings).await, - Commands::Project { - cmd: ProjectCommand::Get { project_id }, + Commands::Secret { cmd } => { + command::secret::process_command(cmd, client, organization_id, output_settings).await } - | Commands::Get { - cmd: GetCommand::Project { project_id }, - } => command::project::get(client, project_id, output_settings).await, - - Commands::Project { - cmd: ProjectCommand::Create { name }, - } - | Commands::Create { - cmd: CreateCommand::Project { name }, - } => command::project::create(client, organization_id, name, output_settings).await, - - Commands::Project { - cmd: ProjectCommand::Edit { project_id, name }, - } - | Commands::Edit { - cmd: EditCommand::Project { project_id, name }, - } => { - command::project::edit(client, organization_id, project_id, name, output_settings).await - } - - Commands::Project { - cmd: ProjectCommand::Delete { project_ids }, - } - | Commands::Delete { - cmd: DeleteCommand::Project { project_ids }, - } => command::project::delete(client, project_ids).await, - - Commands::Secret { - cmd: SecretCommand::List { project_id }, - } - | Commands::List { - cmd: ListCommand::Secrets { project_id }, - } => command::secret::list(client, organization_id, project_id, output_settings).await, - - Commands::Secret { - cmd: SecretCommand::Get { secret_id }, - } - | Commands::Get { - cmd: GetCommand::Secret { secret_id }, - } => command::secret::get(client, secret_id, output_settings).await, - - Commands::Secret { - cmd: - SecretCommand::Create { - key, - value, - note, - project_id, - }, - } - | Commands::Create { - cmd: - CreateCommand::Secret { - key, - value, - note, - project_id, - }, - } => { - command::secret::create( - client, - organization_id, - SecretCreateCommandModel { - key, - value, - note, - project_id, - }, - output_settings, - ) - .await - } - - Commands::Secret { - cmd: - SecretCommand::Edit { - secret_id, - key, - value, - note, - project_id, - }, - } - | Commands::Edit { - cmd: - EditCommand::Secret { - secret_id, - key, - value, - note, - project_id, - }, - } => { - command::secret::edit( - client, - organization_id, - SecretEditCommandModel { - id: secret_id, - key, - value, - note, - project_id, - }, - output_settings, - ) - .await - } - - Commands::Secret { - cmd: SecretCommand::Delete { secret_ids }, - } - | Commands::Delete { - cmd: DeleteCommand::Secret { secret_ids }, - } => command::secret::delete(client, secret_ids).await, Commands::Config { .. } | Commands::Completions { .. } => { unreachable!() From f9d134abf93e5afa16a20f5f2641718b69e3e506 Mon Sep 17 00:00:00 2001 From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Date: Wed, 26 Jun 2024 11:26:41 -0500 Subject: [PATCH 07/11] [SM-1175] Add sm-1175 to the bws changelog (#860) Add removal of deprecated commands to changelog --- crates/bws/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bws/CHANGELOG.md b/crates/bws/CHANGELOG.md index 25cec1164..447f7cad6 100644 --- a/crates/bws/CHANGELOG.md +++ b/crates/bws/CHANGELOG.md @@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Removed + +- The deprecated `action type` commands are now removed. Please use `type action` instead. (#836) + ## [0.5.0] - 2024-04-26 ### Added From d43d1cb45557b0828901ff0ab8a2ee8311ac5b9f Mon Sep 17 00:00:00 2001 From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:38:19 -0500 Subject: [PATCH 08/11] [SM-1262] Update cpp documentation (#854) Clean up C++ documentation and add clearer macOS examples. This includes fixing shell commands formatting. --- languages/cpp/CMakeBuild.md | 50 +++++++++---- languages/cpp/ExampleUse.md | 70 ----------------- languages/cpp/examples/ExampleUse.md | 108 +++++++++++++++++++++++++++ 3 files changed, 142 insertions(+), 86 deletions(-) delete mode 100644 languages/cpp/ExampleUse.md create mode 100644 languages/cpp/examples/ExampleUse.md diff --git a/languages/cpp/CMakeBuild.md b/languages/cpp/CMakeBuild.md index 4c7c29814..cb148069e 100644 --- a/languages/cpp/CMakeBuild.md +++ b/languages/cpp/CMakeBuild.md @@ -1,33 +1,51 @@ -# CMAKE build +# CMake Build -## INTRODUCTION +## Introduction -Cmake is used to build the c++ Bitwarden client library. Output should be placed in the build directory. The output contains two dynamic libraries: one that we are building `BitwardenClient` and another that the building library uses `bitwarden_c`. +Cmake is used to build the C++ Bitwarden client library. Output should be placed in the build directory. -## PREREQUISITES +The output contains two dynamic libraries: + +- The C++ client `BitwardenClient` +- The Bitwarden library used by the C++ client `bitwarden_c`. + +See how to use these libraries in the [example use guide](./examples/ExampleUse.md) + +## Prerequisites - Cmake installed, minimum version 3.15 - `schemas.hpp` generated into `include` directory - installed `nlohmann-json` library - installed `boost` library -## BUILD commands +## Build Commands -One should be in the root directory of the c++ wrapper (the same level where is CMakeLists.txt placed). Paths of the three libraries should be placed inside the cmake build command: +One should be in the root directory of the C++ wrapper (the same level where is CMakeLists.txt placed). Paths of the three libraries should be placed inside the cmake build command: -$ mkdir build -$ cd build -$ cmake .. -DNLOHMANN=/path/to/include/nlohmann -DBOOST=/path/to/include/boost -DTARGET=relative/path/to/libbitwarden_c -$ cmake --build . +```bash +mkdir -p build +cd build +cmake .. -DNLOHMANN=/path/to/include/nlohmann -DBOOST=/path/to/include/boost -DTARGET=relative/path/to/libbitwarden_c +cmake --build . +``` +## Example +### macOS -## Example +#### Install Prerequisites -macOS: +```bash +brew install cmake +brew install boost +brew install nlohmann-json +``` -$ mkdir build -$ cd build -$ cmake .. -DNLOHMANN=/opt/hombrew/include -DBOOST=/opt/homebrew/include -DTARGET=../../target/release/libbitwarden_c.dylib -$ cmake --build . +#### Build +```bash +mkdir -p build +cd build +cmake .. -DNLOHMANN=/opt/homebrew/include -DBOOST=/opt/homebrew/include -DTARGET=../../target/release/libbitwarden_c.dylib +cmake --build . +``` diff --git a/languages/cpp/ExampleUse.md b/languages/cpp/ExampleUse.md deleted file mode 100644 index 579cd0e67..000000000 --- a/languages/cpp/ExampleUse.md +++ /dev/null @@ -1,70 +0,0 @@ -# EXAMPLES - - -## PREREQUISITES - -### BITWARDEN Libraries -One should have two libraries at the same path: -- `BitwardeClient` -- `bitwarden_c` - -It should look like `libBitwardeClient.dylib` and `libbitwarden_c.dylib` for the macOS. - -For Linux: `libBitwardeClient.so` and `libbitwarden_c.so` -For Windows: `BitwardeClient.dll` and `bitwarden_c.dll` - -### INCLUDE directory - -`include` directory contains: -- `BitwardenLibrary.h` -- `BitwardenClient.h` -- `BitwardenSettings.h` -- `CommandRunner.h` -- `Projects.h` -- `Secrets.h` -- `schemas.hpp` - -### Other libraries -- `nlohmann-json` (https://github.com/nlohmann/json) -- `boost` (https://www.boost.org/) - - -### COMPILING - -One could use g++/clang++ for compiling. -Example of the folder structure (macOS): - ---root - --build - `libBitwardenClient.dylib` - `libbitwarden_c.dylib` - --include - --`BitwardenLibrary.h` - --`BitwardenClient.h` - --`BitwardenSettings.h` - --`CommandRunner.h` - --`Projects.h` - --`Secrets.h` - --`schemas.hpp` - --examples - --`Wrapper.cpp` - - -1. $ export ACCESS_TOKEN=<"access-token"> -2. $ export ORGANIZATION_ID=<"organization-id"> -3. $ export DYLD_LIBRARY_PATH=/path/to/your/library:$DYLD_LIBRARY_PATH - -The last step is neccessary to add the path for the dynamic library (macOS). -For the Linux one should use: -$ export LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH -For the Windows: -$ set PATH=%PATH%;C:\path\to\your\library - -4. $ cd examples -5. $ clang++ -std=c++20 -I../include -I/path/to/include/nlohmann -I/path/to/include/boost -L../build/ -o MyBitwardenApp Wrapper.cpp -lBitwardenClient -ldl - -for Windows `-ldl` should be excluded, - -The result is `MyBitwardenApp` in the `examples` directory, and one can run it from the `examples` directory: - -6. $ ./MyBitwardenApp diff --git a/languages/cpp/examples/ExampleUse.md b/languages/cpp/examples/ExampleUse.md new file mode 100644 index 000000000..f5ec6f6ff --- /dev/null +++ b/languages/cpp/examples/ExampleUse.md @@ -0,0 +1,108 @@ +# Examples + +## Prerequisites + +### Bitwarden Libraries + +Have the two Bitwarden libraries at the same path: + +- `BitwardenClient` +- `bitwarden_c` + +For each OS the library files will be the following: + +- macOS: `libBitwardenClient.dylib` and `libbitwarden_c.dylib` +- Linux: `libBitwardenClient.so` and `libbitwarden_c.so` +- Windows: `BitwardenClient.dll` and `bitwarden_c.dll` + +Follow the [cmake build guide](../CMakeBuild.md) to create the libraries locally. + +### Include Directory + +`include` directory contains: + +- `BitwardenLibrary.h` +- `BitwardenClient.h` +- `BitwardenSettings.h` +- `CommandRunner.h` +- `Projects.h` +- `Secrets.h` +- `schemas.hpp` + +### Other Libraries + +- `nlohmann-json` () +- `boost` () + +### Compiling + +Use g++/clang++ for compiling. + +Example of the folder structure (macOS): + +```text +--root + --build + `libBitwardenClient.dylib` + `libbitwarden_c.dylib` + --include + --`BitwardenLibrary.h` + --`BitwardenClient.h` + --`BitwardenSettings.h` + --`CommandRunner.h` + --`Projects.h` + --`Secrets.h` + --`schemas.hpp` + --examples + --`Wrapper.cpp` +``` + +Set the environment variable path for the Bitwarden libraries. + +For macOS: + +```bash +export DYLD_LIBRARY_PATH=/path/to/your/library:$DYLD_LIBRARY_PATH +``` + +For Linux: + +```bash +export LD_LIBRARY_PATH=/path/to/your/library:$LD_LIBRARY_PATH +``` + +For Windows: + +```shell + set "PATH=%PATH%;C:\path\to\your\library" +``` + +Set environment variables used in `Wrapper.cpp`: + +```bash +export ACCESS_TOKEN=<"access-token"> +export ORGANIZATION_ID=<"organization-id"> +export API_URL=http://localhost:4000 +export IDENTITY_URL=http://localhost:33656 +``` + +Compile: + +```bash +cd examples +clang++ -std=c++20 -I../include -I/path/to/include/nlohmann -I/path/to/include/boost -L../build/ -o MyBitwardenApp Wrapper.cpp -lBitwardenClient -ldl +``` + +for Windows `-ldl` should be excluded, + +for macOS nlohmann and boost libraries installed with homebrew the following can be used: + +```bash +-I/opt/homebrew/include +``` + +The result is `MyBitwardenApp` in the `examples` directory, and can be ran from the `examples` directory: + +```bash +./MyBitwardenApp +``` From 84597751740714a50fcd047de855844b7f861e3d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:37:13 +0200 Subject: [PATCH 09/11] [deps]: Update @types/node to v18.19.39 (#856) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [@types/node](https://togithub.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node) ([source](https://togithub.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node)) | [`18.19.34` -> `18.19.39`](https://renovatebot.com/diffs/npm/@types%2fnode/18.19.34/18.19.39) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@types%2fnode/18.19.39?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/@types%2fnode/18.19.39?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/@types%2fnode/18.19.34/18.19.39?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@types%2fnode/18.19.34/18.19.39?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Configuration 📅 **Schedule**: Branch creation - "every 2nd week starting on the 2 week of the year before 4am on Monday" (UTC), Automerge - At any time (no schedule defined). đŸšĻ **Automerge**: Disabled by config. Please merge this manually once you are satisfied. â™ģ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/bitwarden/sdk). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- languages/js/sdk-client/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/languages/js/sdk-client/package-lock.json b/languages/js/sdk-client/package-lock.json index b9a9882d3..417dbdba4 100644 --- a/languages/js/sdk-client/package-lock.json +++ b/languages/js/sdk-client/package-lock.json @@ -39,9 +39,9 @@ } }, "node_modules/@types/node": { - "version": "18.19.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.34.tgz", - "integrity": "sha512-eXF4pfBNV5DAMKGbI02NnDtWrQ40hAN558/2vvS4gMpMIxaf6JmD7YjnZbq0Q9TDSSkKBamime8ewRoomHdt4g==", + "version": "18.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.39.tgz", + "integrity": "sha512-nPwTRDKUctxw3di5b4TfT3I0sWDiWoPQCZjXhvdkINntwr8lcoVCKsTgnXeRubKIlfnV+eN/HYk6Jb40tbcEAQ==", "dev": true, "license": "MIT", "dependencies": { From 05475f1eb25780f05ed81f775c2c8a809a70daf5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 16:17:03 +0200 Subject: [PATCH 10/11] [deps]: Lock file maintenance (#859) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Update | Change | |---|---| | lockFileMaintenance | All locks refreshed | 🔧 This Pull Request updates lock files to use the latest dependency versions. --- ### Configuration 📅 **Schedule**: Branch creation - "every 2nd week starting on the 2 week of the year before 4am on Monday" (UTC), Automerge - At any time (no schedule defined). đŸšĻ **Automerge**: Disabled by config. Please merge this manually once you are satisfied. â™ģ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. đŸ‘ģ **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://togithub.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://developer.mend.io/github/bitwarden/sdk). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- Cargo.lock | 320 +++++++++-------- crates/bitwarden-napi/package-lock.json | 66 ++-- languages/js/sdk-client/package-lock.json | 117 +++++-- package-lock.json | 404 ++++++++++++++++------ 4 files changed, 593 insertions(+), 314 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a1c0dbe4d..bbf507a2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,9 +118,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -183,7 +183,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "async-compat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f68a707c1feb095d8c07f8a65b9f506b117d30af431cab89374357de7c11461b" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" dependencies = [ "futures-core", "futures-io", @@ -232,9 +232,15 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.3.0" @@ -349,9 +355,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitwarden" @@ -760,15 +766,15 @@ dependencies = [ "tempfile", "thiserror", "tokio", - "toml 0.8.12", + "toml 0.8.14", "uuid", ] [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" [[package]] name = "byteorder" @@ -790,9 +796,9 @@ checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -837,9 +843,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.97" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" [[package]] name = "cesu8" @@ -930,9 +936,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.5" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" +checksum = "fbca90c87c2a04da41e95d1856e8bcd22f159bdbfa147314d2ce5218057b0e58" dependencies = [ "clap", ] @@ -946,14 +952,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clap_mangen" @@ -1027,8 +1033,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" dependencies = [ "crossterm 0.27.0", - "strum 0.26.2", - "strum_macros 0.26.2", + "strum 0.26.3", + "strum_macros 0.26.4", "unicode-width", ] @@ -1127,9 +1133,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -1191,9 +1197,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" @@ -1217,7 +1223,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "crossterm_winapi", "libc", "parking_lot", @@ -1289,7 +1295,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -1337,7 +1343,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -1359,7 +1365,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core 0.20.9", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -1493,9 +1499,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -1710,7 +1716,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -1834,15 +1840,15 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http", "indexmap 2.2.6", "slab", @@ -1947,12 +1953,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1960,9 +1966,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -2017,9 +2023,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" dependencies = [ "bytes", "futures-channel", @@ -2124,7 +2130,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "crossterm 0.25.0", "dyn-clone", "fuzzy-matcher", @@ -2228,11 +2234,11 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.5.2", + "spin", ] [[package]] @@ -2243,9 +2249,9 @@ checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", "windows-targets 0.52.5", @@ -2263,7 +2269,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", ] @@ -2275,9 +2281,9 @@ checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2291,9 +2297,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" @@ -2346,9 +2352,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -2367,11 +2373,11 @@ dependencies = [ [[package]] name = "napi" -version = "2.16.6" +version = "2.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc300228808a0e6aea5a58115c82889240bcf8dab16fc25ad675b33e454b368" +checksum = "a1bd081bbaef43600fd2c5dd4c525b8ecea7dfdacf40ebc674e87851dce6559e" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "ctor", "napi-derive", "napi-sys", @@ -2387,23 +2393,23 @@ checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" [[package]] name = "napi-derive" -version = "2.16.5" +version = "2.16.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0e034ddf6155192cf83f267ede763fe6c164dfa9971585436b16173718d94c4" +checksum = "70a8a778fd367b13c64232e58632514b795514ece491ce136d96e976d34a3eb8" dependencies = [ "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "napi-derive-backend" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff2c00437f3b3266391eb5e6aa25d0029187daf5caf05b8e3271468fb5ae73e" +checksum = "35849e64596ecd467e1ac897153364a1ffd09b1d79b32ebad94ef8980ac73311" dependencies = [ "convert_case", "once_cell", @@ -2411,7 +2417,7 @@ dependencies = [ "quote", "regex", "semver", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -2453,9 +2459,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -2599,9 +2605,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2671,7 +2677,7 @@ name = "passkey-types" version = "0.2.1" source = "git+https://github.com/bitwarden/passkey-rs?rev=c48c2ddfd6b884b2d754432576c66cb2b1985a3a#c48c2ddfd6b884b2d754432576c66cb2b1985a3a" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "ciborium", "coset", "data-encoding", @@ -2752,7 +2758,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -2816,9 +2822,9 @@ dependencies = [ [[package]] name = "plotters" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" dependencies = [ "num-traits", "plotters-backend", @@ -2829,15 +2835,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" [[package]] name = "plotters-svg" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" dependencies = [ "plotters-backend", ] @@ -2871,9 +2877,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2966,7 +2972,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -2979,7 +2985,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -3105,11 +3111,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -3225,7 +3231,7 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin 0.9.8", + "spin", "untrusted", "windows-sys 0.52.0", ] @@ -3274,7 +3280,7 @@ version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -3326,9 +3332,9 @@ checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" [[package]] name = "rustls-platform-verifier" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5f0d26fa1ce3c790f9590868f0109289a044acb954525f933e2aa3b871c157d" +checksum = "3e3beb939bcd33c269f4bf946cc829fcd336370267c4a927ac0399c84a3151a1" dependencies = [ "core-foundation", "core-foundation-sys", @@ -3364,9 +3370,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" @@ -3416,7 +3422,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -3448,7 +3454,7 @@ checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -3529,25 +3535,25 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" dependencies = [ "indexmap 2.2.6", "itoa", @@ -3574,14 +3580,14 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -3625,7 +3631,7 @@ dependencies = [ "darling 0.20.9", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -3759,12 +3765,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -3816,9 +3816,9 @@ dependencies = [ [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "strum_macros" @@ -3830,27 +3830,27 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "supports-color" @@ -3874,9 +3874,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.63" +version = "2.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" dependencies = [ "proc-macro2", "quote", @@ -3940,22 +3940,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4011,9 +4011,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" dependencies = [ "tinyvec_macros", ] @@ -4026,9 +4026,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -4043,13 +4043,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4087,9 +4087,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", @@ -4099,18 +4099,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap 2.2.6", "serde", @@ -4132,7 +4132,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -4153,7 +4152,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4167,7 +4165,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4232,7 +4230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a615d6c2764852a2e88a4f16e9ce1ea49bb776b5872956309e170d63a042a34f" dependencies = [ "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4279,9 +4277,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "uniffi" @@ -4343,12 +4341,12 @@ dependencies = [ [[package]] name = "uniffi_checksum_derive" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e86ccd44c138ba12b9132decbabeed84bf686ebe4b6538a5e489a243a7c2c9" +checksum = "d5c400339a9d1d17be34257d0b407e91d64af335e5b4fa49f4bf28467fc8d635" dependencies = [ "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4380,7 +4378,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.63", + "syn 2.0.68", "toml 0.5.11", "uniffi_meta", ] @@ -4443,9 +4441,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna", @@ -4454,15 +4452,15 @@ dependencies = [ [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.8.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" dependencies = [ "getrandom", "serde", @@ -4528,7 +4526,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", "wasm-bindgen-shared", ] @@ -4562,7 +4560,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4595,7 +4593,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] @@ -4807,9 +4805,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] @@ -4850,9 +4848,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "serde", "zeroize_derive", @@ -4866,7 +4864,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.63", + "syn 2.0.68", ] [[package]] diff --git a/crates/bitwarden-napi/package-lock.json b/crates/bitwarden-napi/package-lock.json index 708d7369f..8f21b16fd 100644 --- a/crates/bitwarden-napi/package-lock.json +++ b/crates/bitwarden-napi/package-lock.json @@ -22,6 +22,7 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -34,6 +35,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -42,13 +44,15 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -59,6 +63,7 @@ "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.18.3.tgz", "integrity": "sha512-L0f4kP0dyG8W5Qtc7MtP73VvLLrOLyRcUEBzknIfu8Jk4Jfhrsx1ItMHgyalYqMSslWdY3ojEfAaU5sx1VyeQQ==", "dev": true, + "license": "MIT", "bin": { "napi": "scripts/index.js" }, @@ -74,41 +79,47 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.12.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", - "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -117,10 +128,14 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -129,19 +144,22 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -150,13 +168,15 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -196,10 +216,11 @@ } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -213,19 +234,22 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } diff --git a/languages/js/sdk-client/package-lock.json b/languages/js/sdk-client/package-lock.json index 417dbdba4..209365dc2 100644 --- a/languages/js/sdk-client/package-lock.json +++ b/languages/js/sdk-client/package-lock.json @@ -16,6 +16,7 @@ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -33,6 +34,7 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -53,6 +55,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -65,6 +68,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -76,13 +80,15 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -92,6 +98,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -103,13 +110,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -123,19 +132,22 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -148,16 +160,18 @@ } }, "node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -174,6 +188,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -182,13 +197,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -203,19 +220,21 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", + "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", "dev": true, + "license": "ISC", "engines": { "node": "14 || >=16.14" } }, "node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -227,19 +246,28 @@ } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -249,6 +277,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -265,6 +294,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -283,6 +313,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -295,6 +326,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -304,6 +336,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -316,6 +349,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -334,6 +368,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -348,6 +383,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -356,13 +392,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -375,6 +413,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -391,6 +430,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -403,15 +443,17 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -424,13 +466,15 @@ "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -446,6 +490,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -464,6 +509,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -481,6 +527,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -490,6 +537,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -504,13 +552,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -525,6 +575,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, diff --git a/package-lock.json b/package-lock.json index 42d079262..1b95e9906 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,10 +19,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz", - "integrity": "sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -35,6 +36,7 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -46,13 +48,15 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.1.3.tgz", "integrity": "sha512-q9U8v/n9qbkd2zDYjuX3qtlbl+OIyI9zF+zQhZjfYOE9VMDH7tfcUSJ9p0lXoY3lxmGFne09yi4iiNeQUwV7AA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -70,6 +74,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -82,6 +87,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -93,13 +99,15 @@ "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -117,6 +125,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -132,6 +141,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -149,6 +159,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -157,13 +168,15 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -174,6 +187,7 @@ "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -183,6 +197,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.2.tgz", "integrity": "sha512-Z6GuOUdNQjP7FX+OuV2Ybyamse+/e0BFdTWBX5JxpBDKA+YkdLynDgG6HTF04zy6e9zPa19UX0WA2VDoehwhXQ==", "dev": true, + "license": "MIT", "peerDependencies": { "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "axios": "^1.3.1", @@ -194,6 +209,7 @@ "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.0.tgz", "integrity": "sha512-DGv34UHsZBxCM3H5QGE2XE/+oLJzz5+714JQjBhjD9VccFlQs3LRxo/epso4l7nJIiNlZkPyIUC8WzfU/5RTsQ==", "dev": true, + "license": "MIT", "dependencies": { "iterare": "1.2.1", "tslib": "2.6.2", @@ -224,6 +240,7 @@ "integrity": "sha512-N06P5ncknW/Pm8bj964WvLIZn2gNhHliCBoAO1LeBvNImYkecqKcrmLbY49Fa1rmMfEM3MuBHeDys3edeuYAOA==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", @@ -261,6 +278,7 @@ "resolved": "https://registry.npmjs.org/@nuxtjs/opencollective/-/opencollective-0.3.2.tgz", "integrity": "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "consola": "^2.15.0", @@ -280,6 +298,7 @@ "integrity": "sha512-4JKyrk55ohQK2FcuZbPdNvxdyXD14jjOIvE8hYjJ+E1cHbRbfXQXbYnjTODFE52Gx8eAxz8C9icuhDYDLn7nww==", "dev": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { "@nestjs/axios": "3.0.2", "@nestjs/common": "10.3.0", @@ -316,6 +335,7 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -325,31 +345,36 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.12.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", - "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "undici-types": "~5.26.4" @@ -359,13 +384,15 @@ "version": "1.19.25", "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.25.tgz", "integrity": "sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -374,10 +401,11 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -386,10 +414,14 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -399,6 +431,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -411,6 +444,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -426,6 +460,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -435,6 +470,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -449,19 +485,22 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dev": true, + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -472,7 +511,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -492,13 +532,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -510,6 +552,7 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -519,7 +562,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz", "integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/buffer": { "version": "5.7.1", @@ -540,6 +584,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -550,6 +595,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -565,13 +611,15 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -584,6 +632,7 @@ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -596,6 +645,7 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10" } @@ -605,6 +655,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -616,6 +667,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -633,6 +685,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -641,13 +694,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -659,13 +714,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -678,6 +735,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12" } @@ -686,19 +744,22 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concurrently": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz", "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "date-fns": "^2.16.1", @@ -721,6 +782,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -733,6 +795,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -747,19 +810,22 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/consola": { "version": "2.15.3", "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/console.table": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", "dev": true, + "license": "MIT", "dependencies": { "easy-table": "1.1.0" }, @@ -771,13 +837,15 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", "dev": true, + "license": "MIT", "dependencies": { "node-fetch": "^2.6.12" } @@ -787,6 +855,7 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -801,6 +870,7 @@ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -813,10 +883,11 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -834,6 +905,7 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -846,6 +918,7 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -855,6 +928,7 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -863,13 +937,15 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/easy-table": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", "dev": true, + "license": "MIT", "optionalDependencies": { "wcwidth": ">=1.0.1" } @@ -878,13 +954,15 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -894,6 +972,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.0" } @@ -903,6 +982,7 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -912,6 +992,7 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } @@ -921,6 +1002,7 @@ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -934,13 +1016,15 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -962,6 +1046,7 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -972,10 +1057,11 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", "dev": true, + "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -992,6 +1078,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -1004,6 +1091,7 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -1018,6 +1106,7 @@ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1031,13 +1120,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1046,7 +1137,9 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1066,13 +1159,15 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -1094,6 +1189,7 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1103,6 +1199,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -1116,6 +1213,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -1141,13 +1239,16 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1157,13 +1258,15 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/inquirer": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -1190,6 +1293,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1199,6 +1303,7 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1208,6 +1313,7 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1219,28 +1325,32 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/iterare": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==", "dev": true, + "license": "ISC", "engines": { "node": ">=6" } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -1258,13 +1368,15 @@ "version": "3.7.7", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz", "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -1276,13 +1388,15 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -1295,10 +1409,11 @@ } }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.0.tgz", + "integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==", "dev": true, + "license": "ISC", "engines": { "node": "14 || >=16.14" } @@ -1307,13 +1422,15 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1323,6 +1440,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -1335,6 +1453,7 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1344,6 +1463,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1356,15 +1476,17 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -1373,25 +1495,29 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -1412,6 +1538,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -1421,6 +1548,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -1436,6 +1564,7 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -1459,21 +1588,31 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1483,6 +1622,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1492,6 +1632,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -1507,13 +1648,15 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", "integrity": "sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -1523,6 +1666,7 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -1538,6 +1682,7 @@ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -1546,13 +1691,15 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/quicktype-core": { "version": "23.0.81", "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.0.81.tgz", "integrity": "sha512-iJQpCEzSQIkffJPS5NC+0w+Rq9faGgz09L+WIbseu1toFfj+M/3KTG5jhzdY/uN88fWosAom2fMoEADA403+rQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@glideapps/ts-necessities": "2.1.3", "@types/urijs": "^1.19.19", @@ -1590,6 +1737,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -1600,6 +1748,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.4.2.tgz", "integrity": "sha512-Lk/fICSyIhodxy1IDK2HazkeGjSmezAWX2egdtJnYhtzKEsBPJowlI6F6LPb5tqIQILrMbx22S5o3GuJavPusA==", "dev": true, + "license": "MIT", "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -1616,6 +1765,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1629,19 +1779,22 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1651,6 +1804,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -1664,6 +1818,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -1682,21 +1837,24 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/rimraf/node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.2.tgz", + "integrity": "sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -1709,10 +1867,11 @@ } }, "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1728,6 +1887,7 @@ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -1737,6 +1897,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -1759,19 +1920,22 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -1784,6 +1948,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1792,13 +1957,15 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -1807,13 +1974,15 @@ "version": "0.0.2-1", "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -1823,6 +1992,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1838,6 +2008,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -1852,6 +2023,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1865,6 +2037,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -1877,6 +2050,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -1888,19 +2062,22 @@ "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tiny-inflate": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -1912,13 +2089,15 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -1928,6 +2107,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -1970,13 +2150,15 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1989,6 +2171,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -1998,10 +2181,11 @@ } }, "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.18.0.tgz", + "integrity": "sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -2015,6 +2199,7 @@ "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", "dev": true, + "license": "MIT", "dependencies": { "@lukeed/csprng": "^1.0.0" }, @@ -2027,6 +2212,7 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/unicode-properties": { @@ -2034,6 +2220,7 @@ "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", "dev": true, + "license": "MIT", "dependencies": { "base64-js": "^1.3.0", "unicode-trie": "^2.0.0" @@ -2044,6 +2231,7 @@ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", "dev": true, + "license": "MIT", "dependencies": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" @@ -2053,13 +2241,15 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -2068,25 +2258,29 @@ "version": "1.19.11", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } @@ -2095,13 +2289,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -2112,6 +2308,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -2126,13 +2323,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2148,6 +2347,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2164,22 +2364,25 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yaml": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", - "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, @@ -2192,6 +2395,7 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -2210,6 +2414,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -2219,6 +2424,7 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } From 56547d7e8e44e89f391baa387b57e4102cb611d2 Mon Sep 17 00:00:00 2001 From: tangowithfoxtrot <5676771+tangowithfoxtrot@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:02:11 -0700 Subject: [PATCH 11/11] [SM-1130] - add install scripts (#645) ## Type of change - [ ] Bug fix - [ ] New feature development - [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc) - [x] Build/deploy pipeline (DevOps) - [x] Other ## Objective Allow easy installation of `bws` on most systems with: `curl | sh` on Linux and macOS or `iwr | iex` on Windows ## Code changes - **crates/bws/scripts/install.(sh|ps1):** added install scripts that will download `bws` from GitHub Releases, validate the checksums, and install it. I am unsure if this is the _best_ place to house these scripts and would welcome suggestions for other places these might belong. - **.github/workflows/version-bump.yml:** added version bumps for the install scripts ## Before you submit - Please add **unit tests** where it makes sense to do so --- .github/workflows/version-bump.yml | 9 +- crates/bws/README.md | 20 +++- crates/bws/scripts/install.ps1 | 108 +++++++++++++++++ crates/bws/scripts/install.sh | 180 +++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+), 4 deletions(-) create mode 100755 crates/bws/scripts/install.ps1 create mode 100755 crates/bws/scripts/install.sh diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 24a2c7997..6c10d51bf 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -103,16 +103,19 @@ jobs: run: cargo set-version -p bitwarden-napi ${{ inputs.version_number }} ### bitwarden - - name: Bump bitwarden crate Version if: ${{ inputs.project == 'bitwarden' }} run: cargo set-version -p bitwarden ${{ inputs.version_number }} ### bws - - name: Bump bws Version if: ${{ inputs.project == 'bws' }} - run: cargo set-version -p bws ${{ inputs.version_number }} + run: | + cargo set-version -p bws ${{ inputs.version_number }} + # bump the version in install.sh + sed -i 's/DEFAULT_BWS_VERSION="[0-9]\+\.[0-9]\+\.[0-9]\+"/DEFAULT_BWS_VERSION="${{ inputs.version_number }}"/' ./crates/bws/scripts/install.sh + # bump the version in install.ps1 + sed -i 's/\$defaultBwsVersion = "[0-9]\+\.[0-9]\+\.[0-9]\+"/\$defaultBwsVersion = "${{ inputs.version_number }}"/' ./crates/bws/scripts/install.ps1 ### python - name: Bump python-sdk Version diff --git a/crates/bws/README.md b/crates/bws/README.md index ace5210f1..2b9c8c99c 100644 --- a/crates/bws/README.md +++ b/crates/bws/README.md @@ -6,11 +6,29 @@ and might be missing some functionality. ## Install +We offer three ways to install bws: + +### Cargo (crates.io) + +Download bws via `cargo` from [crates.io](https://crates.io): + ```bash cargo install bws ``` -Or download a pre-built binary from the [Releases](https://github.com/bitwarden/sdk/releases) page. +### Install Script (from GitHub Releases) + +Linux/macOS: `curl https://bws.bitwarden.com/install | sh` + +Windows: `iwr https://bws.bitwarden.com/install | iex` + +An optional `-u/--uninstall` flag can be passed to the POSIX script to uninstall the CLI. The +PowerShell version accepts an equivalent `-Uninstall` flag. The uninstallation process will remove +the `bws` binary and the configuration directory (`~/.bws`). + +### GitHub Releases (Manual) + +Download a pre-built binary from the [Releases](https://github.com/bitwarden/sdk/releases) page. ## Usage diff --git a/crates/bws/scripts/install.ps1 b/crates/bws/scripts/install.ps1 new file mode 100755 index 000000000..f39846c20 --- /dev/null +++ b/crates/bws/scripts/install.ps1 @@ -0,0 +1,108 @@ +param ( + [switch]$Uninstall +) + +$ErrorActionPreference = "Stop" + +$defaultBwsVersion = "0.5.0" +$bwsVersion = if ($env:bwsVersion) { $env:bwsVersion } else { $defaultBwsVersion } +$installDir = [Environment]::GetFolderPath([Environment+SpecialFolder]::LocalApplicationData) | Join-Path -ChildPath "Programs" | Join-Path -ChildPath "Bitwarden" + +# https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processor#properties +$processorArch = (Get-CimInstance -ClassName Win32_Processor).Architecture +if ($processorArch -eq 9) { + $arch = "x86_64" +} elseif ($processorArch -eq 12) { + $arch = "aarch64" +} else { + throw "Unsupported architecture: $processorArch" +} + +function Test-BwsInstallation { + $existingBws = Get-Command bws -ErrorAction SilentlyContinue + if ($null -ne $existingBws) { + $userInput = Read-Host "bws is already installed at $($existingBws.Source). Do you want to overwrite it? (Y/N)" + if ($userInput -ne "Y") { + Write-Host "Installation cancelled by user." + exit + } + } +} + +function Invoke-BwsDownload { + Write-Host "Detected architecture: $arch" + + $bwsUrl = "https://github.com/bitwarden/sdk/releases/download/bws-v$bwsVersion/bws-$arch-pc-windows-msvc-$bwsVersion.zip" + Write-Host "Downloading bws from: $bwsUrl" + $outputPath = Join-Path $env:TEMP "bws.zip" + Invoke-WebRequest -Uri $bwsUrl -OutFile $outputPath + return $outputPath +} + +function Test-Checksum { + param($zipPath) + Write-Host "Validating checksum..." + + $checksumUrl = "https://github.com/bitwarden/sdk/releases/download/bws-v$bwsVersion/bws-sha256-checksums-$bwsVersion.txt" + $checksumFile = Join-Path $env:TEMP "bws-checksums.txt" + Invoke-WebRequest -Uri $checksumUrl -OutFile $checksumFile + + $expectedChecksum = (Get-Content $checksumFile | Where-Object { $_ -match "bws-$arch-pc-windows-msvc-$bwsVersion.zip" }).Split(" ")[0] + $actualChecksum = (Get-FileHash -Algorithm SHA256 -Path $zipPath).Hash + + if ($actualChecksum -ne $expectedChecksum) { + throw "Checksum validation failed. Expected: $expectedChecksum, Actual: $actualChecksum" + } else { + Write-Host "Checksum validation successful." + } +} + +function Install-Bws { + param($zipPath) + Write-Host "Installing bws..." + New-Item -ItemType Directory -Force -Path $installDir | Out-Null + Expand-Archive -Force $zipPath -DestinationPath $installDir + Write-Host "bws installed to $installDir" + setx PATH "$env:PATH;$installDir" + Write-Host "$installDir has been added to your PATH" + Write-Host "Please restart your shell to use bws" +} + +function Test-Bws { + Write-Host "Checking bws..." + $bwsPath = Join-Path $installDir "bws.exe" + if (Test-Path $bwsPath) { + Write-Host "bws is installed at $bwsPath" + } else { + throw "bws is not installed" + } +} + +function Remove-Bws { + Write-Host "Uninstalling bws..." + + if (Test-Path $installDir) { + Remove-Item -Path $installDir -Recurse -Force + Write-Host "bws uninstalled from $installDir" + } else { + Write-Host "bws installation directory not found at $installDir. Skipping removal." + } + + $configDir = "$env:USERPROFILE\.bws" + if (Test-Path $configDir -PathType Container) { + Remove-Item -Path $configDir -Recurse -Force + Write-Host "bws config directory removed from $configDir" + } else { + Write-Host "bws config directory not found at $configDir. Skipping removal." + } +} + +if ($Uninstall) { + Remove-Bws +} else { + Test-BwsInstallation + $zipPath = Invoke-BwsDownload + Test-Checksum -zipPath $zipPath + Install-Bws -zipPath $zipPath + Test-Bws +} diff --git a/crates/bws/scripts/install.sh b/crates/bws/scripts/install.sh new file mode 100755 index 000000000..126ae9e22 --- /dev/null +++ b/crates/bws/scripts/install.sh @@ -0,0 +1,180 @@ +#!/bin/sh + +################################################## +# An installer for the bws command line utility. # +################################################## + +DEFAULT_BWS_VERSION="0.5.0" +BWS_VERSION="${BWS_VERSION:-$DEFAULT_BWS_VERSION}" + +main() { + case "$1" in + -u | --uninstall) + uninstall_bws + ;; + *) + check_required + platform_detect + arch_detect + download_bws + validate_checksum + install_bws + ;; + esac +} + +error() { + echo "$1" >&2 + echo "Exiting..." >&2 + exit 1 +} + +check_required() { + if ! command -v curl >/dev/null && ! command -v wget >/dev/null; then + error "curl or wget is required to download bws." + fi + + if ! command -v unzip >/dev/null; then + error "unzip is required to install bws." + fi +} + +can_sudo() { + if command -v sudo >/dev/null; then + echo "Attempting to install bws with sudo. Please enter your password if prompted." + if sudo -v 2>/dev/null; then + echo "sudo is available and we have the necessary permissions." + echo "Installing bws to /usr/local/bin..." + return 0 + else + echo "sudo is available, but we failed to authenticate." + return 1 + fi + else + echo "sudo is not available." + return 1 + fi +} + +platform_detect() { + if [ "$(uname -s)" = "Linux" ]; then + PLATFORM="unknown-linux-gnu" + elif [ "$(uname -s)" = "Darwin" ]; then + PLATFORM="apple-darwin" + else + error "Unsupported platform: $(uname -s)" + fi +} + +arch_detect() { + if [ "$(uname -m)" = "x86_64" ]; then + ARCH="x86_64" + elif [ "$(uname -m)" = "aarch64" ]; then # Linux uname output + ARCH="aarch64" + elif [ "$(uname -m)" = "arm64" ]; then # Darwin uname output + ARCH="aarch64" + else + error "Unsupported architecture: $(uname -m)" + fi +} + +checksum() { + if command -v sha256sum >/dev/null; then + sha256sum "$1" + else + shasum -a 256 "$1" + fi +} + +downloader() { + if command -v curl >/dev/null; then + curl -L -o "$2" "$1" + else + wget -O "$2" "$1" + fi +} + +extract() { + unzip -o "$1" -d "$2" +} + +download_bws() { + bws_url="https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" + echo "Downloading bws from: $bws_url" + tmp_dir="$(mktemp -d)" + downloader "$bws_url" "$tmp_dir/bws.zip" +} + +validate_checksum() { + checksum_url="https://github.com/bitwarden/sdk/releases/download/bws-v${BWS_VERSION}/bws-sha256-checksums-${BWS_VERSION}.txt" + echo "Downloading checksum file from: $checksum_url" + checksum_file="$tmp_dir/bws-checksums.txt" + downloader "$checksum_url" "$checksum_file" + + expected_checksum="$(grep "bws-${ARCH}-${PLATFORM}-${BWS_VERSION}.zip" "$checksum_file" | awk '{print $1}')" + actual_checksum="$(checksum "$tmp_dir/bws.zip" | awk '{print $1}')" + + if [ "$actual_checksum" != "$expected_checksum" ]; then + error "Checksum validation failed. Expected: $expected_checksum, Actual: $actual_checksum" + else + echo "Checksum validation successful." + fi +} + +install_bws() { + echo "Installing bws..." + extract "$tmp_dir/bws.zip" "$tmp_dir" + chmod +x "$tmp_dir/bws" + + if can_sudo; then + sudo install -m 755 "$tmp_dir/bws" /usr/local/bin/bws + + if ! command -v bws >/dev/null; then + error "Installation failed. bws was not found in /usr/local/bin" + fi + + echo "bws installed to /usr/local/bin/bws" + else + echo "Installing to your \$HOME directory..." + user_bin_dir="${HOME}/.local/bin" + mkdir -p "${user_bin_dir}" + install -m 755 "$tmp_dir/bws" "${user_bin_dir}/bws" + + if ! command -v "${user_bin_dir}/bws" >/dev/null; then + error "Installation failed. bws was not found in ${user_bin_dir}" + fi + + echo "bws installed at ${user_bin_dir}/bws" + echo "Please add ${user_bin_dir} to your PATH by adding the following line to your ~/.profile or shell rc file:" + echo "export PATH=\"\$PATH:${user_bin_dir}\"" + fi + + rm -rf "$tmp_dir" +} + +uninstall_bws() { + if command -v bws >/dev/null; then + echo "Uninstalling bws..." + if can_sudo; then + sudo rm "$(command -v bws)" + else + rm "$(command -v bws)" + fi + + # Safely remove the configuration directory + if [ -n "$HOME" ]; then + echo "Removing bws configuration directory at ${HOME}/.bws" + echo "If you use another directory for your configuration, you may want to remove it manually." + rm -rf "${HOME}/.bws" + else + echo "HOME environment variable is not set. Cannot safely remove .bws directory." + fi + + echo "bws uninstalled successfully." + else + echo "bws is not installed." + fi + exit 0 +} + +main "$@"