From 801141f90ed47a647d0b8852d502345a0cfe4688 Mon Sep 17 00:00:00 2001 From: ttalty <144813356+ttalty@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:17:25 -0500 Subject: [PATCH] [PM-166] [PM-198] - Add Event Logs for CLI Actions (#6527) * Added the DeviceType changes for windows CLI * Event logging for CLI commands * Changing the icons to cli icons --- apps/cli/src/bw.ts | 19 +++++++++++++++++++ apps/cli/src/commands/get.command.ts | 13 ++++++++++++- apps/cli/src/commands/list.command.ts | 16 +++++++++++++++- apps/cli/src/commands/serve.command.ts | 6 ++++-- .../services/cli-platform-utils.service.ts | 8 ++++---- apps/cli/src/tools/export.command.ts | 10 +++++++++- apps/cli/src/tools/send/send.program.ts | 3 ++- apps/cli/src/vault.program.ts | 12 +++++++++--- apps/web/src/app/core/event.service.ts | 6 ++++++ apps/web/src/locales/en/messages.json | 3 +++ libs/common/src/enums/device-type.enum.ts | 6 ++++++ libs/common/src/services/api.service.ts | 5 ++++- 12 files changed, 93 insertions(+), 14 deletions(-) diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 9b0f2ed9ed..191e71c4b8 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -4,6 +4,8 @@ import * as path from "path"; import * as program from "commander"; import * as jsdom from "jsdom"; +import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; +import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; @@ -44,6 +46,8 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory import { NoopMessagingService } from "@bitwarden/common/platform/services/noop-messaging.service"; import { StateService } from "@bitwarden/common/platform/services/state.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; +import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; +import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { SearchService } from "@bitwarden/common/services/search.service"; import { SettingsService } from "@bitwarden/common/services/settings.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; @@ -116,6 +120,8 @@ export class Main { vaultTimeoutService: VaultTimeoutService; vaultTimeoutSettingsService: VaultTimeoutSettingsService; syncService: SyncService; + eventCollectionService: EventCollectionServiceAbstraction; + eventUploadService: EventUploadServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction; passwordStrengthService: PasswordStrengthServiceAbstraction; totpService: TotpService; @@ -452,6 +458,19 @@ export class Main { this.sendProgram = new SendProgram(this); this.userVerificationApiService = new UserVerificationApiService(this.apiService); + + this.eventUploadService = new EventUploadService( + this.apiService, + this.stateService, + this.logService + ); + + this.eventCollectionService = new EventCollectionService( + this.cipherService, + this.stateService, + this.organizationService, + this.eventUploadService + ); } async run() { diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 5e1552066a..1c7f37706c 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -1,9 +1,11 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { EventType } from "@bitwarden/common/enums"; import { CardExport } from "@bitwarden/common/models/export/card.export"; import { CipherExport } from "@bitwarden/common/models/export/cipher.export"; import { CollectionExport } from "@bitwarden/common/models/export/collection.export"; @@ -53,7 +55,8 @@ export class GetCommand extends DownloadCommand { private stateService: StateService, private searchService: SearchService, private apiService: ApiService, - private organizationService: OrganizationService + private organizationService: OrganizationService, + private eventCollectionService: EventCollectionService ) { super(cryptoService); } @@ -137,6 +140,14 @@ export class GetCommand extends DownloadCommand { return Response.multipleResults(decCipher.map((c) => c.id)); } } + + this.eventCollectionService.collect( + EventType.Cipher_ClientViewed, + id, + true, + decCipher.organizationId + ); + const res = new CipherResponse(decCipher); return Response.success(res); } diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index f69926ad99..bd30730890 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,7 +1,9 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; +import { EventType } from "@bitwarden/common/enums"; import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -32,7 +34,8 @@ export class ListCommand { private organizationService: OrganizationService, private searchService: SearchService, private organizationUserService: OrganizationUserService, - private apiService: ApiService + private apiService: ApiService, + private eventCollectionService: EventCollectionService ) {} async run(object: string, cmdOptions: Record): Promise { @@ -123,6 +126,17 @@ export class ListCommand { ciphers = this.searchService.searchCiphersBasic(ciphers, options.search, options.trash); } + ciphers.forEach((c, index) => { + // Set upload immediately on the last item in the ciphers collection to avoid the event collection + // service from uploading each time. + this.eventCollectionService.collect( + EventType.Cipher_ClientViewed, + c.id, + index === ciphers.length - 1, + c.organizationId + ); + }); + const res = new ListResponse(ciphers.map((o) => new CipherResponse(o))); return Response.success(res); } diff --git a/apps/cli/src/commands/serve.command.ts b/apps/cli/src/commands/serve.command.ts index 78c7c0c481..5937c51ae6 100644 --- a/apps/cli/src/commands/serve.command.ts +++ b/apps/cli/src/commands/serve.command.ts @@ -66,7 +66,8 @@ export class ServeCommand { this.main.stateService, this.main.searchService, this.main.apiService, - this.main.organizationService + this.main.organizationService, + this.main.eventCollectionService ); this.listCommand = new ListCommand( this.main.cipherService, @@ -75,7 +76,8 @@ export class ServeCommand { this.main.organizationService, this.main.searchService, this.main.organizationUserService, - this.main.apiService + this.main.apiService, + this.main.eventCollectionService ); this.createCommand = new CreateCommand( this.main.cipherService, diff --git a/apps/cli/src/platform/services/cli-platform-utils.service.ts b/apps/cli/src/platform/services/cli-platform-utils.service.ts index e6e25e237b..883270cd09 100644 --- a/apps/cli/src/platform/services/cli-platform-utils.service.ts +++ b/apps/cli/src/platform/services/cli-platform-utils.service.ts @@ -19,14 +19,14 @@ export class CliPlatformUtilsService implements PlatformUtilsService { if (!this.deviceCache) { switch (process.platform) { case "win32": - this.deviceCache = DeviceType.WindowsDesktop; + this.deviceCache = DeviceType.WindowsCLI; break; case "darwin": - this.deviceCache = DeviceType.MacOsDesktop; + this.deviceCache = DeviceType.MacOsCLI; break; case "linux": default: - this.deviceCache = DeviceType.LinuxDesktop; + this.deviceCache = DeviceType.LinuxCLI; break; } } @@ -36,7 +36,7 @@ export class CliPlatformUtilsService implements PlatformUtilsService { getDeviceString(): string { const device = DeviceType[this.getDevice()].toLowerCase(); - return device.replace("desktop", ""); + return device.replace("cli", ""); } getClientType() { diff --git a/apps/cli/src/tools/export.command.ts b/apps/cli/src/tools/export.command.ts index 272901a34c..7b4b040508 100644 --- a/apps/cli/src/tools/export.command.ts +++ b/apps/cli/src/tools/export.command.ts @@ -1,8 +1,10 @@ import * as program from "commander"; import * as inquirer from "inquirer"; +import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; +import { EventType } from "@bitwarden/common/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ExportFormat, @@ -16,7 +18,8 @@ import { CliUtils } from "../utils"; export class ExportCommand { constructor( private exportService: VaultExportServiceAbstraction, - private policyService: PolicyService + private policyService: PolicyService, + private eventCollectionService: EventCollectionService ) {} async run(options: program.OptionValues): Promise { @@ -48,6 +51,11 @@ export class ExportCommand { format === "encrypted_json" ? await this.getProtectedExport(options.password, options.organizationid) : await this.getUnprotectedExport(format, options.organizationid); + + const eventType = options.organizationid + ? EventType.Organization_ClientExportedVault + : EventType.User_ClientExportedVault; + this.eventCollectionService.collect(eventType, null, true, options.organizationid); } catch (e) { return Response.error(e); } diff --git a/apps/cli/src/tools/send/send.program.ts b/apps/cli/src/tools/send/send.program.ts index 48aba023c1..be99fc2ed1 100644 --- a/apps/cli/src/tools/send/send.program.ts +++ b/apps/cli/src/tools/send/send.program.ts @@ -156,7 +156,8 @@ export class SendProgram extends Program { this.main.stateService, this.main.searchService, this.main.apiService, - this.main.organizationService + this.main.organizationService, + this.main.eventCollectionService ); const response = await cmd.run("template", object, null); this.processResponse(response); diff --git a/apps/cli/src/vault.program.ts b/apps/cli/src/vault.program.ts index 85f413a9fe..33d7469491 100644 --- a/apps/cli/src/vault.program.ts +++ b/apps/cli/src/vault.program.ts @@ -116,7 +116,8 @@ export class VaultProgram extends Program { this.main.organizationService, this.main.searchService, this.main.organizationUserService, - this.main.apiService + this.main.apiService, + this.main.eventCollectionService ); const response = await command.run(object, cmd); @@ -189,7 +190,8 @@ export class VaultProgram extends Program { this.main.stateService, this.main.searchService, this.main.apiService, - this.main.organizationService + this.main.organizationService, + this.main.eventCollectionService ); const response = await command.run(object, id, cmd); this.processResponse(response); @@ -489,7 +491,11 @@ export class VaultProgram extends Program { }) .action(async (options) => { await this.exitIfLocked(); - const command = new ExportCommand(this.main.exportService, this.main.policyService); + const command = new ExportCommand( + this.main.exportService, + this.main.policyService, + this.main.eventCollectionService + ); const response = await command.run(options); this.processResponse(response); }); diff --git a/apps/web/src/app/core/event.service.ts b/apps/web/src/app/core/event.service.ts index d3e8f2d158..de75ddc7b4 100644 --- a/apps/web/src/app/core/event.service.ts +++ b/apps/web/src/app/core/event.service.ts @@ -486,6 +486,12 @@ export class EventService { return ["bwi-globe", this.i18nService.t("webVault") + " - IE"]; case DeviceType.Server: return ["bwi-server", this.i18nService.t("server")]; + case DeviceType.WindowsCLI: + return ["bwi-cli", this.i18nService.t("cli") + " - Windows"]; + case DeviceType.MacOsCLI: + return ["bwi-cli", this.i18nService.t("cli") + " - macOS"]; + case DeviceType.LinuxCLI: + return ["bwi-cli", this.i18nService.t("cli") + " - Linux"]; case DeviceType.UnknownBrowser: return [ "bwi-globe", diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 7aface1641..44bb8a4522 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -2762,6 +2762,9 @@ "webVault": { "message": "Web vault" }, + "cli": { + "message": "CLI" + }, "bitWebVault": { "message": "Bitwarden Web vault" }, diff --git a/libs/common/src/enums/device-type.enum.ts b/libs/common/src/enums/device-type.enum.ts index 663c482489..1b8574a4c4 100644 --- a/libs/common/src/enums/device-type.enum.ts +++ b/libs/common/src/enums/device-type.enum.ts @@ -22,6 +22,9 @@ export enum DeviceType { SafariExtension = 20, SDK = 21, Server = 22, + WindowsCLI = 23, + MacOsCLI = 24, + LinuxCLI = 25, } export const MobileDeviceTypes: Set = new Set([ @@ -35,4 +38,7 @@ export const DesktopDeviceTypes: Set = new Set([ DeviceType.MacOsDesktop, DeviceType.LinuxDesktop, DeviceType.UWP, + DeviceType.WindowsCLI, + DeviceType.MacOsCLI, + DeviceType.LinuxCLI, ]); diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 51ffdcff88..2275c2015f 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -171,7 +171,10 @@ export class ApiService implements ApiServiceAbstraction { this.isDesktopClient = this.device === DeviceType.WindowsDesktop || this.device === DeviceType.MacOsDesktop || - this.device === DeviceType.LinuxDesktop; + this.device === DeviceType.LinuxDesktop || + this.device === DeviceType.WindowsCLI || + this.device === DeviceType.MacOsCLI || + this.device === DeviceType.LinuxCLI; } // Auth APIs