mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 06:13:38 +00:00
[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
This commit is contained in:
@@ -4,6 +4,8 @@ import * as path from "path";
|
|||||||
import * as program from "commander";
|
import * as program from "commander";
|
||||||
import * as jsdom from "jsdom";
|
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 { 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 { 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";
|
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 { NoopMessagingService } from "@bitwarden/common/platform/services/noop-messaging.service";
|
||||||
import { StateService } from "@bitwarden/common/platform/services/state.service";
|
import { StateService } from "@bitwarden/common/platform/services/state.service";
|
||||||
import { AuditService } from "@bitwarden/common/services/audit.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 { SearchService } from "@bitwarden/common/services/search.service";
|
||||||
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
import { SettingsService } from "@bitwarden/common/services/settings.service";
|
||||||
import { TotpService } from "@bitwarden/common/services/totp.service";
|
import { TotpService } from "@bitwarden/common/services/totp.service";
|
||||||
@@ -116,6 +120,8 @@ export class Main {
|
|||||||
vaultTimeoutService: VaultTimeoutService;
|
vaultTimeoutService: VaultTimeoutService;
|
||||||
vaultTimeoutSettingsService: VaultTimeoutSettingsService;
|
vaultTimeoutSettingsService: VaultTimeoutSettingsService;
|
||||||
syncService: SyncService;
|
syncService: SyncService;
|
||||||
|
eventCollectionService: EventCollectionServiceAbstraction;
|
||||||
|
eventUploadService: EventUploadServiceAbstraction;
|
||||||
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
passwordGenerationService: PasswordGenerationServiceAbstraction;
|
||||||
passwordStrengthService: PasswordStrengthServiceAbstraction;
|
passwordStrengthService: PasswordStrengthServiceAbstraction;
|
||||||
totpService: TotpService;
|
totpService: TotpService;
|
||||||
@@ -452,6 +458,19 @@ export class Main {
|
|||||||
this.sendProgram = new SendProgram(this);
|
this.sendProgram = new SendProgram(this);
|
||||||
|
|
||||||
this.userVerificationApiService = new UserVerificationApiService(this.apiService);
|
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() {
|
async run() {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { AuditService } from "@bitwarden/common/abstractions/audit.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 { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
import { TotpService } from "@bitwarden/common/abstractions/totp.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
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 { CardExport } from "@bitwarden/common/models/export/card.export";
|
||||||
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
import { CipherExport } from "@bitwarden/common/models/export/cipher.export";
|
||||||
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
import { CollectionExport } from "@bitwarden/common/models/export/collection.export";
|
||||||
@@ -53,7 +55,8 @@ export class GetCommand extends DownloadCommand {
|
|||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private organizationService: OrganizationService
|
private organizationService: OrganizationService,
|
||||||
|
private eventCollectionService: EventCollectionService
|
||||||
) {
|
) {
|
||||||
super(cryptoService);
|
super(cryptoService);
|
||||||
}
|
}
|
||||||
@@ -137,6 +140,14 @@ export class GetCommand extends DownloadCommand {
|
|||||||
return Response.multipleResults(decCipher.map((c) => c.id));
|
return Response.multipleResults(decCipher.map((c) => c.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.eventCollectionService.collect(
|
||||||
|
EventType.Cipher_ClientViewed,
|
||||||
|
id,
|
||||||
|
true,
|
||||||
|
decCipher.organizationId
|
||||||
|
);
|
||||||
|
|
||||||
const res = new CipherResponse(decCipher);
|
const res = new CipherResponse(decCipher);
|
||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
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 { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
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 { 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 { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
@@ -32,7 +34,8 @@ export class ListCommand {
|
|||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private searchService: SearchService,
|
private searchService: SearchService,
|
||||||
private organizationUserService: OrganizationUserService,
|
private organizationUserService: OrganizationUserService,
|
||||||
private apiService: ApiService
|
private apiService: ApiService,
|
||||||
|
private eventCollectionService: EventCollectionService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run(object: string, cmdOptions: Record<string, any>): Promise<Response> {
|
async run(object: string, cmdOptions: Record<string, any>): Promise<Response> {
|
||||||
@@ -123,6 +126,17 @@ export class ListCommand {
|
|||||||
ciphers = this.searchService.searchCiphersBasic(ciphers, options.search, options.trash);
|
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)));
|
const res = new ListResponse(ciphers.map((o) => new CipherResponse(o)));
|
||||||
return Response.success(res);
|
return Response.success(res);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ export class ServeCommand {
|
|||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.searchService,
|
this.main.searchService,
|
||||||
this.main.apiService,
|
this.main.apiService,
|
||||||
this.main.organizationService
|
this.main.organizationService,
|
||||||
|
this.main.eventCollectionService
|
||||||
);
|
);
|
||||||
this.listCommand = new ListCommand(
|
this.listCommand = new ListCommand(
|
||||||
this.main.cipherService,
|
this.main.cipherService,
|
||||||
@@ -75,7 +76,8 @@ export class ServeCommand {
|
|||||||
this.main.organizationService,
|
this.main.organizationService,
|
||||||
this.main.searchService,
|
this.main.searchService,
|
||||||
this.main.organizationUserService,
|
this.main.organizationUserService,
|
||||||
this.main.apiService
|
this.main.apiService,
|
||||||
|
this.main.eventCollectionService
|
||||||
);
|
);
|
||||||
this.createCommand = new CreateCommand(
|
this.createCommand = new CreateCommand(
|
||||||
this.main.cipherService,
|
this.main.cipherService,
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ export class CliPlatformUtilsService implements PlatformUtilsService {
|
|||||||
if (!this.deviceCache) {
|
if (!this.deviceCache) {
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case "win32":
|
case "win32":
|
||||||
this.deviceCache = DeviceType.WindowsDesktop;
|
this.deviceCache = DeviceType.WindowsCLI;
|
||||||
break;
|
break;
|
||||||
case "darwin":
|
case "darwin":
|
||||||
this.deviceCache = DeviceType.MacOsDesktop;
|
this.deviceCache = DeviceType.MacOsCLI;
|
||||||
break;
|
break;
|
||||||
case "linux":
|
case "linux":
|
||||||
default:
|
default:
|
||||||
this.deviceCache = DeviceType.LinuxDesktop;
|
this.deviceCache = DeviceType.LinuxCLI;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ export class CliPlatformUtilsService implements PlatformUtilsService {
|
|||||||
|
|
||||||
getDeviceString(): string {
|
getDeviceString(): string {
|
||||||
const device = DeviceType[this.getDevice()].toLowerCase();
|
const device = DeviceType[this.getDevice()].toLowerCase();
|
||||||
return device.replace("desktop", "");
|
return device.replace("cli", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
getClientType() {
|
getClientType() {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import * as program from "commander";
|
import * as program from "commander";
|
||||||
import * as inquirer from "inquirer";
|
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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||||
|
import { EventType } from "@bitwarden/common/enums";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import {
|
import {
|
||||||
ExportFormat,
|
ExportFormat,
|
||||||
@@ -16,7 +18,8 @@ import { CliUtils } from "../utils";
|
|||||||
export class ExportCommand {
|
export class ExportCommand {
|
||||||
constructor(
|
constructor(
|
||||||
private exportService: VaultExportServiceAbstraction,
|
private exportService: VaultExportServiceAbstraction,
|
||||||
private policyService: PolicyService
|
private policyService: PolicyService,
|
||||||
|
private eventCollectionService: EventCollectionService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async run(options: program.OptionValues): Promise<Response> {
|
async run(options: program.OptionValues): Promise<Response> {
|
||||||
@@ -48,6 +51,11 @@ export class ExportCommand {
|
|||||||
format === "encrypted_json"
|
format === "encrypted_json"
|
||||||
? await this.getProtectedExport(options.password, options.organizationid)
|
? await this.getProtectedExport(options.password, options.organizationid)
|
||||||
: await this.getUnprotectedExport(format, 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) {
|
} catch (e) {
|
||||||
return Response.error(e);
|
return Response.error(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,8 @@ export class SendProgram extends Program {
|
|||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.searchService,
|
this.main.searchService,
|
||||||
this.main.apiService,
|
this.main.apiService,
|
||||||
this.main.organizationService
|
this.main.organizationService,
|
||||||
|
this.main.eventCollectionService
|
||||||
);
|
);
|
||||||
const response = await cmd.run("template", object, null);
|
const response = await cmd.run("template", object, null);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ export class VaultProgram extends Program {
|
|||||||
this.main.organizationService,
|
this.main.organizationService,
|
||||||
this.main.searchService,
|
this.main.searchService,
|
||||||
this.main.organizationUserService,
|
this.main.organizationUserService,
|
||||||
this.main.apiService
|
this.main.apiService,
|
||||||
|
this.main.eventCollectionService
|
||||||
);
|
);
|
||||||
const response = await command.run(object, cmd);
|
const response = await command.run(object, cmd);
|
||||||
|
|
||||||
@@ -189,7 +190,8 @@ export class VaultProgram extends Program {
|
|||||||
this.main.stateService,
|
this.main.stateService,
|
||||||
this.main.searchService,
|
this.main.searchService,
|
||||||
this.main.apiService,
|
this.main.apiService,
|
||||||
this.main.organizationService
|
this.main.organizationService,
|
||||||
|
this.main.eventCollectionService
|
||||||
);
|
);
|
||||||
const response = await command.run(object, id, cmd);
|
const response = await command.run(object, id, cmd);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
@@ -489,7 +491,11 @@ export class VaultProgram extends Program {
|
|||||||
})
|
})
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
await this.exitIfLocked();
|
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);
|
const response = await command.run(options);
|
||||||
this.processResponse(response);
|
this.processResponse(response);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -486,6 +486,12 @@ export class EventService {
|
|||||||
return ["bwi-globe", this.i18nService.t("webVault") + " - IE"];
|
return ["bwi-globe", this.i18nService.t("webVault") + " - IE"];
|
||||||
case DeviceType.Server:
|
case DeviceType.Server:
|
||||||
return ["bwi-server", this.i18nService.t("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:
|
case DeviceType.UnknownBrowser:
|
||||||
return [
|
return [
|
||||||
"bwi-globe",
|
"bwi-globe",
|
||||||
|
|||||||
@@ -2762,6 +2762,9 @@
|
|||||||
"webVault": {
|
"webVault": {
|
||||||
"message": "Web vault"
|
"message": "Web vault"
|
||||||
},
|
},
|
||||||
|
"cli": {
|
||||||
|
"message": "CLI"
|
||||||
|
},
|
||||||
"bitWebVault": {
|
"bitWebVault": {
|
||||||
"message": "Bitwarden Web vault"
|
"message": "Bitwarden Web vault"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ export enum DeviceType {
|
|||||||
SafariExtension = 20,
|
SafariExtension = 20,
|
||||||
SDK = 21,
|
SDK = 21,
|
||||||
Server = 22,
|
Server = 22,
|
||||||
|
WindowsCLI = 23,
|
||||||
|
MacOsCLI = 24,
|
||||||
|
LinuxCLI = 25,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MobileDeviceTypes: Set<DeviceType> = new Set([
|
export const MobileDeviceTypes: Set<DeviceType> = new Set([
|
||||||
@@ -35,4 +38,7 @@ export const DesktopDeviceTypes: Set<DeviceType> = new Set([
|
|||||||
DeviceType.MacOsDesktop,
|
DeviceType.MacOsDesktop,
|
||||||
DeviceType.LinuxDesktop,
|
DeviceType.LinuxDesktop,
|
||||||
DeviceType.UWP,
|
DeviceType.UWP,
|
||||||
|
DeviceType.WindowsCLI,
|
||||||
|
DeviceType.MacOsCLI,
|
||||||
|
DeviceType.LinuxCLI,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -171,7 +171,10 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
this.isDesktopClient =
|
this.isDesktopClient =
|
||||||
this.device === DeviceType.WindowsDesktop ||
|
this.device === DeviceType.WindowsDesktop ||
|
||||||
this.device === DeviceType.MacOsDesktop ||
|
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
|
// Auth APIs
|
||||||
|
|||||||
Reference in New Issue
Block a user