From ae290cf8b51d89a37e6b2f92b58bbb093934df60 Mon Sep 17 00:00:00 2001 From: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Date: Tue, 26 May 2026 07:56:22 -0400 Subject: [PATCH] [SM-1927] Updating code so that if the machine acct name is corrupted data (#19898) * Updating code so that if the machine acct name is corrupted data it doesn't lock users out of the list views * Adding logging * Fixing bugs with corrupted machine accounts preventing export --- .../models/view/service-account.view.ts | 1 + .../service-account.service.ts | 50 +++++++++++++++---- .../service-accounts-list.component.html | 28 +++++++++-- .../services/sm-porting-api.service.ts | 8 ++- .../access-policies/access-policy.service.ts | 18 ++++--- 5 files changed, 85 insertions(+), 20 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/models/view/service-account.view.ts b/bitwarden_license/bit-web/src/app/secrets-manager/models/view/service-account.view.ts index 3df383ef96c..c28f607d7c0 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/models/view/service-account.view.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/models/view/service-account.view.ts @@ -6,6 +6,7 @@ export class ServiceAccountView { name: string; creationDate: string; revisionDate: string; + decryptionError: boolean = false; } export class ServiceAccountSecretsDetailsView extends ServiceAccountView { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.service.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.service.ts index 2706bf99f3b..23e47ddb4b5 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.service.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.service.ts @@ -7,8 +7,12 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; -import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { + DECRYPT_ERROR, + EncString, +} from "@bitwarden/common/key-management/crypto/models/enc-string"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { OrganizationId } from "@bitwarden/common/types/guid"; import { KeyService } from "@bitwarden/key-management"; @@ -38,6 +42,7 @@ export class ServiceAccountService { private apiService: ApiService, private encryptService: EncryptService, private accountService: AccountService, + private logService: LogService, ) {} private getOrganizationKey$(organizationId: string) { @@ -167,12 +172,18 @@ export class ServiceAccountService { serviceAccountView.organizationId = serviceAccountResponse.organizationId; serviceAccountView.creationDate = serviceAccountResponse.creationDate; serviceAccountView.revisionDate = serviceAccountResponse.revisionDate; - serviceAccountView.name = serviceAccountResponse.name - ? await this.encryptService.decryptString( - new EncString(serviceAccountResponse.name), - organizationKey, - ) - : null; + + if (serviceAccountResponse.name) { + const name = await this.decryptField( + new EncString(serviceAccountResponse.name), + organizationKey, + ); + serviceAccountView.name = name.value; + serviceAccountView.decryptionError = name.error; + } else { + serviceAccountView.name = null; + } + return serviceAccountView; } @@ -186,9 +197,15 @@ export class ServiceAccountService { view.creationDate = response.creationDate; view.revisionDate = response.revisionDate; view.accessToSecrets = response.accessToSecrets; - view.name = response.name - ? await this.encryptService.decryptString(new EncString(response.name), organizationKey) - : null; + + if (response.name) { + const name = await this.decryptField(new EncString(response.name), organizationKey); + view.name = name.value; + view.decryptionError = name.error; + } else { + view.name = null; + } + return view; } @@ -203,4 +220,17 @@ export class ServiceAccountService { }), ); } + + private async decryptField( + encString: EncString, + organizationKey: SymmetricCryptoKey, + ): Promise<{ value: string; error: boolean }> { + try { + const decrypted = await this.encryptService.decryptString(encString, organizationKey); + return { value: decrypted, error: false }; + } catch (error) { + this.logService.error("Error decrypting service account field", error); + return { value: DECRYPT_ERROR, error: true }; + } + } } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html index 65f951ce857..11e32520ccc 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.html @@ -58,9 +58,31 @@ - - {{ serviceAccount.name }} - + @if (serviceAccount.decryptionError) { + + {{ serviceAccount.name }} + + + } @else { + + {{ serviceAccount.name }} + + } {{ serviceAccount.accessToSecrets }} diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.ts b/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.ts index c489c61b680..4e6577b7196 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/settings/services/sm-porting-api.service.ts @@ -163,12 +163,18 @@ export class SecretsManagerPortingApiService { exportData.secrets.map(async (s) => { const secret = new SecretsManagerExportSecret(); - [secret.key, secret.value, secret.note] = await Promise.all([ + const decryptionResults = await Promise.allSettled([ this.encryptService.decryptString(new EncString(s.key), orgKey), this.encryptService.decryptString(new EncString(s.value), orgKey), this.encryptService.decryptString(new EncString(s.note), orgKey), ]); + secret.key = + decryptionResults[0].status === "fulfilled" ? decryptionResults[0].value : DECRYPT_ERROR; + secret.value = + decryptionResults[1].status === "fulfilled" ? decryptionResults[1].value : DECRYPT_ERROR; + secret.note = + decryptionResults[2].status === "fulfilled" ? decryptionResults[2].value : DECRYPT_ERROR; secret.id = s.id; secret.projectIds = s.projectIds; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.ts index 74886c0ab62..d881fbfc7c1 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/access-policies/access-policy.service.ts @@ -412,15 +412,21 @@ export class AccessPolicyService { ): Promise { return await Promise.all( responses.map(async (response) => { + let serviceAccountName = null; + if (response.serviceAccountName) { + try { + serviceAccountName = await this.encryptService.decryptString( + new EncString(response.serviceAccountName), + orgKey, + ); + } catch { + serviceAccountName = DECRYPT_ERROR; + } + } return { ...this.createBaseAccessPolicyView(response), serviceAccountId: response.serviceAccountId, - serviceAccountName: response.serviceAccountName - ? await this.encryptService.decryptString( - new EncString(response.serviceAccountName), - orgKey, - ) - : null, + serviceAccountName, }; }), );