From 93f2ca62bca7ec803d5a58c1958bfa7130b2ce79 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Mon, 26 Jun 2023 09:17:30 -0400 Subject: [PATCH 01/10] SM-807: Fix edit secret, allow updating the project a secret is in, and other small changes --- crates/bitwarden/src/commands/secrets.rs | 2 +- .../src/sdk/request/secrets_request.rs | 1 + crates/bws/src/main.rs | 20 ++++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/crates/bitwarden/src/commands/secrets.rs b/crates/bitwarden/src/commands/secrets.rs index 898015ca7..6abf9bfe9 100644 --- a/crates/bitwarden/src/commands/secrets.rs +++ b/crates/bitwarden/src/commands/secrets.rs @@ -116,7 +116,7 @@ pub(crate) async fn update_secret( key: enc.encrypt(input.key.as_bytes(), org_id)?.to_string(), value: enc.encrypt(input.value.as_bytes(), org_id)?.to_string(), note: enc.encrypt(input.note.as_bytes(), org_id)?.to_string(), - project_ids: None, + project_ids: input.project_ids.clone(), }); let config = client.get_api_configurations().await; diff --git a/crates/bitwarden/src/sdk/request/secrets_request.rs b/crates/bitwarden/src/sdk/request/secrets_request.rs index 846a45683..6ed7c4acc 100644 --- a/crates/bitwarden/src/sdk/request/secrets_request.rs +++ b/crates/bitwarden/src/sdk/request/secrets_request.rs @@ -34,6 +34,7 @@ pub struct SecretPutRequest { pub key: String, pub value: String, pub note: String, + pub project_ids: Option>, } #[derive(Serialize, Deserialize, Debug, JsonSchema)] diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 4df9503bf..5042649dd 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -117,11 +117,12 @@ enum SecretCommand { note: Option, #[arg(long, help = "The ID of the project this secret will be added to")] - project_id: Option, + project_id: Uuid, }, Delete { secret_ids: Vec, }, + #[clap(group = ArgGroup::new("edit_field").required(true).multiple(true))] Edit { secret_id: Uuid, #[arg(long, group = "edit_field")] @@ -130,6 +131,8 @@ enum SecretCommand { value: Option, #[arg(long, group = "edit_field")] note: Option, + #[arg(long, group = "edit_field")] + project_id: Option, }, Get { secret_id: Uuid, @@ -183,7 +186,7 @@ enum CreateCommand { note: Option, #[arg(long, help = "The ID of the project this secret will be added to")] - project_id: Option, + project_id: Uuid, }, } @@ -204,6 +207,8 @@ enum EditCommand { value: Option, #[arg(long, group = "edit_field")] note: Option, + #[arg(long, group = "edit_field")] + project_id: Option, }, } @@ -470,7 +475,7 @@ async fn process_commands() -> Result<()> { key, value, note: note.unwrap_or_default(), - project_ids: project_id.map(|p| vec![p]), + project_ids: Some(vec![project_id]), }) .await?; serialize_response(secret, cli.output, color); @@ -483,6 +488,7 @@ async fn process_commands() -> Result<()> { key, value, note, + project_id, }, } | Commands::Edit { @@ -492,6 +498,7 @@ async fn process_commands() -> Result<()> { key, value, note, + project_id, }, } => { let old_secret = client @@ -509,6 +516,13 @@ async fn process_commands() -> Result<()> { 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); From b117e206d910bceb8cbbae32491badaa73cb2538 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Mon, 26 Jun 2023 09:39:06 -0400 Subject: [PATCH 02/10] SM-807: Update schemas --- .../bitwarden-napi/src-ts/bitwarden_client/schemas.ts | 2 ++ languages/csharp/schemas.cs | 3 +++ languages/js_webassembly/bitwarden_client/schemas.ts | 2 ++ languages/python/BitwardenClient/schemas.py | 6 +++++- support/schemas/request/Command.json | 10 ++++++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/bitwarden-napi/src-ts/bitwarden_client/schemas.ts b/crates/bitwarden-napi/src-ts/bitwarden_client/schemas.ts index c1322bdfc..8f4a4eb11 100644 --- a/crates/bitwarden-napi/src-ts/bitwarden_client/schemas.ts +++ b/crates/bitwarden-napi/src-ts/bitwarden_client/schemas.ts @@ -355,6 +355,7 @@ export interface SecretPutRequest { * Organization ID of the secret to modify */ organizationId: string; + projectIds?: string[] | null; value: string; } @@ -1067,6 +1068,7 @@ const typeMap: any = { { json: "key", js: "key", typ: "" }, { json: "note", js: "note", typ: "" }, { json: "organizationId", js: "organizationId", typ: "" }, + { json: "projectIds", js: "projectIds", typ: u(undefined, u(a(""), null)) }, { json: "value", js: "value", typ: "" }, ], false), "SyncRequest": o([ diff --git a/languages/csharp/schemas.cs b/languages/csharp/schemas.cs index 4a7ab7f7d..84843a58d 100644 --- a/languages/csharp/schemas.cs +++ b/languages/csharp/schemas.cs @@ -440,6 +440,9 @@ public partial class SecretPutRequest [JsonProperty("organizationId")] public Guid OrganizationId { get; set; } + [JsonProperty("projectIds")] + public Guid[] ProjectIds { get; set; } + [JsonProperty("value")] public string Value { get; set; } } diff --git a/languages/js_webassembly/bitwarden_client/schemas.ts b/languages/js_webassembly/bitwarden_client/schemas.ts index c1322bdfc..8f4a4eb11 100644 --- a/languages/js_webassembly/bitwarden_client/schemas.ts +++ b/languages/js_webassembly/bitwarden_client/schemas.ts @@ -355,6 +355,7 @@ export interface SecretPutRequest { * Organization ID of the secret to modify */ organizationId: string; + projectIds?: string[] | null; value: string; } @@ -1067,6 +1068,7 @@ const typeMap: any = { { json: "key", js: "key", typ: "" }, { json: "note", js: "note", typ: "" }, { json: "organizationId", js: "organizationId", typ: "" }, + { json: "projectIds", js: "projectIds", typ: u(undefined, u(a(""), null)) }, { json: "value", js: "value", typ: "" }, ], false), "SyncRequest": o([ diff --git a/languages/python/BitwardenClient/schemas.py b/languages/python/BitwardenClient/schemas.py index 592b761f2..a3ab0702f 100644 --- a/languages/python/BitwardenClient/schemas.py +++ b/languages/python/BitwardenClient/schemas.py @@ -479,6 +479,7 @@ class SecretPutRequest: """Organization ID of the secret to modify""" organization_id: UUID value: str + project_ids: Optional[List[UUID]] = None @staticmethod def from_dict(obj: Any) -> 'SecretPutRequest': @@ -488,7 +489,8 @@ def from_dict(obj: Any) -> 'SecretPutRequest': note = from_str(obj.get("note")) organization_id = UUID(obj.get("organizationId")) value = from_str(obj.get("value")) - return SecretPutRequest(id, key, note, organization_id, value) + project_ids = from_union([from_none, lambda x: from_list(lambda x: UUID(x), x)], obj.get("projectIds")) + return SecretPutRequest(id, key, note, organization_id, value, project_ids) def to_dict(self) -> dict: result: dict = {} @@ -497,6 +499,8 @@ def to_dict(self) -> dict: result["note"] = from_str(self.note) result["organizationId"] = str(self.organization_id) result["value"] = from_str(self.value) + if self.project_ids is not None: + result["projectIds"] = from_union([from_none, lambda x: from_list(lambda x: str(x), x)], self.project_ids) return result diff --git a/support/schemas/request/Command.json b/support/schemas/request/Command.json index bbfd9e9c6..7ac70812f 100644 --- a/support/schemas/request/Command.json +++ b/support/schemas/request/Command.json @@ -428,6 +428,16 @@ "type": "string", "format": "uuid" }, + "projectIds": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "format": "uuid" + } + }, "value": { "type": "string" } From cae2129fe49134ded09b225b21def471189b29de Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Mon, 26 Jun 2023 10:26:16 -0400 Subject: [PATCH 03/10] SM-807: Add proper error messaging when secrets or projects are deleted. --- crates/bws/src/main.rs | 50 +++++++++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 5042649dd..bb6cfb1d5 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -392,17 +392,31 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Project { project_ids }, } => { - let project_count = project_ids.len(); - - client + let result = client .projects() .delete(ProjectsDeleteRequest { ids: project_ids }) .await?; - if project_count > 1 { - println!("Projects deleted successfully."); + let mut projects_success = 0; + let mut projects_failed: Vec<(Uuid, String)> = Vec::new(); + + for project in result.data.iter() { + match &project.error { + Some(error_message) => { + projects_failed.push((project.id, error_message.to_owned())) + } + None => projects_success += 1, + } + } + + if projects_success > 1 { + println!("{} projects deleted successfully.", projects_success); } else { - println!("Project deleted successfully."); + println!("{} project deleted successfully.", projects_success); + } + + for project in projects_failed { + println!("{}: {}", project.0, project.1); } } @@ -534,12 +548,32 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Secret { secret_ids }, } => { - client + let result = client .secrets() .delete(SecretsDeleteRequest { ids: secret_ids }) .await?; - println!("Secret deleted correctly"); + let mut secrets_success = 0; + let mut secrets_failed: Vec<(Uuid, String)> = Vec::new(); + + for secret in result.data.iter() { + match &secret.error { + Some(error_message) => { + secrets_failed.push((secret.id, error_message.to_owned())) + } + None => secrets_success += 1, + } + } + + if secrets_success > 1 { + println!("{} secrets deleted successfully.", secrets_success); + } else { + println!("{} secret deleted successfully.", secrets_success); + } + + for secret in secrets_failed { + println!("{}: {}", secret.0, secret.1); + } } Commands::Config { .. } => { From 10e985d4542cebf1e8494ffc1683c84c092b9a5f Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Mon, 26 Jun 2023 15:09:58 -0400 Subject: [PATCH 04/10] SM-807: Make project_id a parameter rather than an argument on secret create --- crates/bws/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index bb6cfb1d5..bc6bfc4ef 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -112,12 +112,10 @@ enum SecretCommand { Create { key: String, value: String, + project_id: Uuid, #[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, }, Delete { secret_ids: Vec, From 45fe7430b7eeed209c2bec29ad74e81212ae762f Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 27 Jun 2023 07:21:17 -0400 Subject: [PATCH 05/10] SM-807: Add back project_ids that were lost in the merge conflict resolution --- crates/bitwarden/src/secrets_manager/secrets/update.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bitwarden/src/secrets_manager/secrets/update.rs b/crates/bitwarden/src/secrets_manager/secrets/update.rs index 45acb2158..2a3c77e27 100644 --- a/crates/bitwarden/src/secrets_manager/secrets/update.rs +++ b/crates/bitwarden/src/secrets_manager/secrets/update.rs @@ -20,6 +20,7 @@ pub struct SecretPutRequest { pub key: String, pub value: String, pub note: String, + pub project_ids: Option>, } pub(crate) async fn update_secret( @@ -37,7 +38,7 @@ pub(crate) async fn update_secret( key: enc.encrypt(input.key.as_bytes(), org_id)?.to_string(), value: enc.encrypt(input.value.as_bytes(), org_id)?.to_string(), note: enc.encrypt(input.note.as_bytes(), org_id)?.to_string(), - project_ids: None, + project_ids: input.project_ids.clone(), }); let config = client.get_api_configurations().await; From 30bb03c01bc39d6685bf83815c9ac8e1b54e4178 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 27 Jun 2023 07:32:21 -0400 Subject: [PATCH 06/10] SM-807: Add additional secrets / projects deletion error message when there are errors --- crates/bws/src/main.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index d479100f6..aac5341e8 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -409,6 +409,12 @@ async fn process_commands() -> Result<()> { println!("{} project deleted successfully.", projects_success); } + if projects_failed.len() > 1 { + println!("{} projects had errors:", projects_failed.len()); + } else { + println!("{} project had an error:", projects_failed.len()); + } + for project in projects_failed { println!("{}: {}", project.0, project.1); } @@ -565,6 +571,12 @@ async fn process_commands() -> Result<()> { println!("{} secret deleted successfully.", secrets_success); } + if secrets_failed.len() > 1 { + println!("{} secrets had errors:", secrets_failed.len()); + } else { + println!("{} secret had an error:", secrets_failed.len()); + } + for secret in secrets_failed { println!("{}: {}", secret.0, secret.1); } From 28242ece0c9be46b07a44f884eebaeba82ed409c Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 27 Jun 2023 07:58:12 -0400 Subject: [PATCH 07/10] SM-807: Make failed messaging on projects or secrets delete optional, and other small output fixes --- crates/bws/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index aac5341e8..6645042d5 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -403,7 +403,7 @@ async fn process_commands() -> Result<()> { } } - if projects_success > 1 { + if projects_success == 0 || projects_success > 1 { println!("{} projects deleted successfully.", projects_success); } else { println!("{} project deleted successfully.", projects_success); @@ -411,7 +411,7 @@ async fn process_commands() -> Result<()> { if projects_failed.len() > 1 { println!("{} projects had errors:", projects_failed.len()); - } else { + } else if projects_failed.len() == 1 { println!("{} project had an error:", projects_failed.len()); } @@ -565,7 +565,7 @@ async fn process_commands() -> Result<()> { } } - if secrets_success > 1 { + if secrets_success == 0 || secrets_success > 1 { println!("{} secrets deleted successfully.", secrets_success); } else { println!("{} secret deleted successfully.", secrets_success); @@ -573,7 +573,7 @@ async fn process_commands() -> Result<()> { if secrets_failed.len() > 1 { println!("{} secrets had errors:", secrets_failed.len()); - } else { + } else if secrets_failed.len() == 1 { println!("{} secret had an error:", secrets_failed.len()); } From 032f4e074656b5cce92ef562ecb77516e7c41701 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 27 Jun 2023 09:03:34 -0400 Subject: [PATCH 08/10] SM-807: Add back the project_id help text on secret create --- crates/bws/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index 6645042d5..ec17da921 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -108,6 +108,8 @@ enum SecretCommand { Create { key: String, value: String, + + #[arg(help = "The ID of the project this secret will be added to")] project_id: Uuid, #[arg(long, help = "An optional note to add to the secret")] From b8074ff181501627822ef320e449c7cb419b29e4 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Wed, 28 Jun 2023 09:38:29 -0400 Subject: [PATCH 09/10] SM-807: Update secret/project delete to use a filter_map and not print on 0 successes --- crates/bws/src/main.rs | 46 ++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index ec17da921..d483eab20 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -388,26 +388,23 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Project { project_ids }, } => { + let mut projects_success = project_ids.len(); + let result = client .projects() .delete(ProjectsDeleteRequest { ids: project_ids }) .await?; - let mut projects_success = 0; - let mut projects_failed: Vec<(Uuid, String)> = Vec::new(); - - for project in result.data.iter() { - match &project.error { - Some(error_message) => { - projects_failed.push((project.id, error_message.to_owned())) - } - None => projects_success += 1, - } - } + let projects_failed: Vec<(Uuid, String)> = result + .data + .into_iter() + .filter_map(|r| r.error.map(|e| (r.id, e))) + .collect(); + projects_success -= projects_failed.len(); - if projects_success == 0 || projects_success > 1 { + if projects_success > 1 { println!("{} projects deleted successfully.", projects_success); - } else { + } else if projects_success == 1 { println!("{} project deleted successfully.", projects_success); } @@ -550,26 +547,23 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Secret { secret_ids }, } => { + let mut secrets_success = secret_ids.len(); + let result = client .secrets() .delete(SecretsDeleteRequest { ids: secret_ids }) .await?; - let mut secrets_success = 0; - let mut secrets_failed: Vec<(Uuid, String)> = Vec::new(); - - for secret in result.data.iter() { - match &secret.error { - Some(error_message) => { - secrets_failed.push((secret.id, error_message.to_owned())) - } - None => secrets_success += 1, - } - } + let secrets_failed: Vec<(Uuid, String)> = result + .data + .into_iter() + .filter_map(|r| r.error.map(|e| (r.id, e))) + .collect(); + secrets_success -= secrets_failed.len(); - if secrets_success == 0 || secrets_success > 1 { + if secrets_success > 1 { println!("{} secrets deleted successfully.", secrets_success); - } else { + } else if secrets_success == 1 { println!("{} secret deleted successfully.", secrets_success); } From daf7921b6c4bba6d97328e0bd113c7fa077319af Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Thu, 29 Jun 2023 11:03:51 -0400 Subject: [PATCH 10/10] SM-807: Remove mut refactor --- crates/bws/src/main.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/bws/src/main.rs b/crates/bws/src/main.rs index d483eab20..3b91c0fdf 100644 --- a/crates/bws/src/main.rs +++ b/crates/bws/src/main.rs @@ -388,7 +388,7 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Project { project_ids }, } => { - let mut projects_success = project_ids.len(); + let count = project_ids.len(); let result = client .projects() @@ -400,12 +400,12 @@ async fn process_commands() -> Result<()> { .into_iter() .filter_map(|r| r.error.map(|e| (r.id, e))) .collect(); - projects_success -= projects_failed.len(); + let deleted_projects = count - projects_failed.len(); - if projects_success > 1 { - println!("{} projects deleted successfully.", projects_success); - } else if projects_success == 1 { - println!("{} project deleted successfully.", projects_success); + 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 { @@ -547,7 +547,7 @@ async fn process_commands() -> Result<()> { | Commands::Delete { cmd: DeleteCommand::Secret { secret_ids }, } => { - let mut secrets_success = secret_ids.len(); + let count = secret_ids.len(); let result = client .secrets() @@ -559,12 +559,12 @@ async fn process_commands() -> Result<()> { .into_iter() .filter_map(|r| r.error.map(|e| (r.id, e))) .collect(); - secrets_success -= secrets_failed.len(); + let deleted_secrets = count - secrets_failed.len(); - if secrets_success > 1 { - println!("{} secrets deleted successfully.", secrets_success); - } else if secrets_success == 1 { - println!("{} secret deleted successfully.", secrets_success); + 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 {