From a6430747091b2923e7830ed7b88c867ccd1d046c Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 24 Feb 2023 16:44:24 +0100 Subject: [PATCH] [SM-389] Event log for service account (#4679) --- .../src/app/common/base.events.component.ts | 1 + apps/web/src/app/core/event.service.ts | 22 ++++++++++++++++--- .../organizations/manage/events.component.ts | 10 +++++++++ apps/web/src/locales/en/messages.json | 18 +++++++++++---- .../secrets/secrets.component.html | 3 ++- .../secrets/secrets.component.ts | 7 +++++- .../shared/secrets-list.component.ts | 5 +++++ libs/common/src/enums/eventType.ts | 2 ++ .../src/models/response/event.response.ts | 4 ++++ libs/common/src/models/view/event.view.ts | 2 ++ 10 files changed, 65 insertions(+), 9 deletions(-) diff --git a/apps/web/src/app/common/base.events.component.ts b/apps/web/src/app/common/base.events.component.ts index 0a67a1caf0..c3bcb24cae 100644 --- a/apps/web/src/app/common/base.events.component.ts +++ b/apps/web/src/app/common/base.events.component.ts @@ -139,6 +139,7 @@ export abstract class BaseEventsComponent { type: r.type, installationId: r.installationId, systemUser: r.systemUser, + serviceAccountId: r.serviceAccountId, }); }) ); diff --git a/apps/web/src/app/core/event.service.ts b/apps/web/src/app/core/event.service.ts index 6cf0c052d5..6650d7dcc7 100644 --- a/apps/web/src/app/core/event.service.ts +++ b/apps/web/src/app/core/event.service.ts @@ -36,7 +36,7 @@ export class EventService { } async getEventInfo(ev: EventResponse, options = new EventOptions()): Promise { - const appInfo = this.getAppInfo(ev.deviceType); + const appInfo = this.getAppInfo(ev); const { message, humanReadableMessage } = await this.getEventMessage(ev, options); return { message: message, @@ -410,6 +410,11 @@ export class EventService { case EventType.OrganizationDomain_NotVerified: msg = humanReadableMsg = this.i18nService.t("domainNotVerifiedEvent", ev.domainName); break; + // Secrets Manager + case EventType.Secret_Retrieved: + msg = this.i18nService.t("accessedSecret", this.formatSecretId(ev)); + humanReadableMsg = this.i18nService.t("accessedSecret", this.getShortId(ev.secretId)); + break; default: break; } @@ -419,8 +424,12 @@ export class EventService { }; } - private getAppInfo(deviceType: DeviceType): [string, string] { - switch (deviceType) { + private getAppInfo(ev: EventResponse): [string, string] { + if (ev.serviceAccountId) { + return ["bwi-globe", this.i18nService.t("sdk")]; + } + + switch (ev.deviceType) { case DeviceType.Android: return ["bwi-android", this.i18nService.t("mobile") + " - Android"]; case DeviceType.iOS: @@ -554,6 +563,13 @@ export class EventService { return a.outerHTML; } + formatSecretId(ev: EventResponse): string { + const shortId = this.getShortId(ev.secretId); + const a = this.makeAnchor(shortId); + a.setAttribute("href", "#/sm/" + ev.organizationId + "/secrets?search=" + shortId); + return a.outerHTML; + } + private makeAnchor(shortId: string) { const a = document.createElement("a"); a.title = this.i18nService.t("view"); diff --git a/apps/web/src/app/organizations/manage/events.component.ts b/apps/web/src/app/organizations/manage/events.component.ts index e1c0d46c82..69fbf0965a 100644 --- a/apps/web/src/app/organizations/manage/events.component.ts +++ b/apps/web/src/app/organizations/manage/events.component.ts @@ -152,9 +152,19 @@ export class EventsComponent extends BaseEventsComponent implements OnInit, OnDe } } + if (r.serviceAccountId) { + return { + name: this.i18nService.t("serviceAccount") + " " + this.getShortId(r.serviceAccountId), + }; + } + return null; } + private getShortId(id: string) { + return id?.substring(0, 8); + } + ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 6562e4f5aa..b3ee19154f 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -6420,6 +6420,19 @@ "errorReadingImportFile": { "message": "An error occurred when trying to read the import file" }, + "accessedSecret": { + "message": "Accessed secret $SECRET_ID$.", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, "createSecret": { "message": "Create a secret" }, @@ -6490,16 +6503,13 @@ }, "exposedMasterPasswordDesc": { "message": "Password found in a data breach. Use a unique password to protect your account. Are you sure you want to use an exposed password?" - }, + }, "weakAndExposedMasterPassword": { "message": "Weak and Exposed Master Password" }, "weakAndBreachedMasterPasswordDesc": { "message": "Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?" }, - "important": { - "message": "Important:" - }, "characterMinimum": { "message": "$LENGTH$ character minimum", "placeholders": { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.html index 724f31e571..d706afa56e 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.html @@ -1,5 +1,5 @@ - + diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts index 367416ea89..0ddf04a275 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/secrets/secrets.component.ts @@ -22,7 +22,8 @@ import { SecretService } from "./secret.service"; templateUrl: "./secrets.component.html", }) export class SecretsComponent implements OnInit { - secrets$: Observable; + protected secrets$: Observable; + protected search: string; private organizationId: string; @@ -41,6 +42,10 @@ export class SecretsComponent implements OnInit { return await this.getSecrets(); }) ); + + if (this.route.snapshot.queryParams.search) { + this.search = this.route.snapshot.queryParams.search; + } } private async getSecrets(): Promise { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts index 63d6b9fe4b..77e086bd5f 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts @@ -24,6 +24,11 @@ export class SecretsListComponent implements OnDestroy { } private _secrets: SecretListView[]; + @Input() + set search(search: string) { + this.dataSource.filter = search; + } + @Input() trash: boolean; @Output() editSecretEvent = new EventEmitter(); diff --git a/libs/common/src/enums/eventType.ts b/libs/common/src/enums/eventType.ts index 5caa4b29df..72cd73c39b 100644 --- a/libs/common/src/enums/eventType.ts +++ b/libs/common/src/enums/eventType.ts @@ -78,4 +78,6 @@ export enum EventType { OrganizationDomain_Removed = 2001, OrganizationDomain_Verified = 2002, OrganizationDomain_NotVerified = 2003, + + Secret_Retrieved = 2100, } diff --git a/libs/common/src/models/response/event.response.ts b/libs/common/src/models/response/event.response.ts index 27fc223ab6..bf2c3ac617 100644 --- a/libs/common/src/models/response/event.response.ts +++ b/libs/common/src/models/response/event.response.ts @@ -23,6 +23,8 @@ export class EventResponse extends BaseResponse { installationId: string; systemUser: EventSystemUser; domainName: string; + secretId: string; + serviceAccountId: string; constructor(response: any) { super(response); @@ -44,5 +46,7 @@ export class EventResponse extends BaseResponse { this.installationId = this.getResponseProperty("InstallationId"); this.systemUser = this.getResponseProperty("SystemUser"); this.domainName = this.getResponseProperty("DomainName"); + this.secretId = this.getResponseProperty("SecretId"); + this.serviceAccountId = this.getResponseProperty("ServiceAccountId"); } } diff --git a/libs/common/src/models/view/event.view.ts b/libs/common/src/models/view/event.view.ts index 6b77c0b628..288f21c81f 100644 --- a/libs/common/src/models/view/event.view.ts +++ b/libs/common/src/models/view/event.view.ts @@ -14,6 +14,7 @@ export class EventView { type: EventType; installationId: string; systemUser: EventSystemUser; + serviceAccountId: string; constructor(data: Required) { this.message = data.message; @@ -28,5 +29,6 @@ export class EventView { this.type = data.type; this.installationId = data.installationId; this.systemUser = data.systemUser; + this.serviceAccountId = data.serviceAccountId; } }