1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PS-1906] Extract uploadEvents from EventService into new service (#4108)

* Move event.service to it's own folder

Move abstractions/event.service to abstractions/event/event.service
Move services/event.service to services/event/event.service
Fix all the imports

* Extract event-upload from event.service

Move `uploadEvents` from `EventService` to `EventUploadService`
Create event-upload-service-factory
Fix wiring up all the dependencies

* Remove clearEvents from EventService

clearEvents is only related to uploading events and can be moved into EventUploadService

Change the logout-method to only call EventUploadService.uploadEvents as that also calls clearEvents internally

* Rename EventService to EventCollectionService

Rename libs\common\abstraction\event\event.service.ts to libs\common\abstractions\event\event-collection.service.ts

Rename libs\common\services\event\event.service.ts to libs\common\services\event\event-collection.service.ts

Fix all the imports

Fix up service regristration/instantiation

Reanme \browser\src\background\service_factories\event-service.factory.ts to \browser\src\background\service_factories\event-collection-service.factory.ts

* Move interval to upload events to EventUploadSvc

Move the `init()` from event-collection.service to event-upload.service
Change call-site in web, desktop, browser
This commit is contained in:
Daniel James Smith
2022-12-06 14:47:42 +01:00
committed by GitHub
parent 1dca425dc4
commit 200dd0a1fb
44 changed files with 400 additions and 293 deletions

View File

@@ -1,7 +1,7 @@
import { CdkDragDrop, moveItemInArray } from "@angular/cdk/drag-drop";
import { Directive, Input, OnChanges, SimpleChanges } from "@angular/core";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { CipherType } from "@bitwarden/common/enums/cipherType";
import { EventType } from "@bitwarden/common/enums/eventType";
@@ -25,7 +25,10 @@ export class AddEditCustomFieldsComponent implements OnChanges {
fieldType = FieldType;
eventType = EventType;
constructor(private i18nService: I18nService, private eventService: EventService) {
constructor(
private i18nService: I18nService,
private eventCollectionService: EventCollectionService
) {
this.addFieldTypeOptions = [
{ name: i18nService.t("cfTypeText"), value: FieldType.Text },
{ name: i18nService.t("cfTypeHidden"), value: FieldType.Hidden },
@@ -74,7 +77,10 @@ export class AddEditCustomFieldsComponent implements OnChanges {
const f = field as any;
f.showValue = !f.showValue;
if (this.editMode && f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipher.id
);
}
}

View File

@@ -4,7 +4,7 @@ import { Observable, Subject, takeUntil, concatMap } from "rxjs";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/abstractions/collection.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/abstractions/log.service";
@@ -91,7 +91,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
protected stateService: StateService,
protected collectionService: CollectionService,
protected messagingService: MessagingService,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
protected policyService: PolicyService,
private logService: LogService,
protected passwordRepromptService: PasswordRepromptService,
@@ -266,7 +266,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.folders$ = this.folderService.folderViews$;
if (this.editMode && this.previousCipherId !== this.cipherId) {
this.eventService.collect(EventType.Cipher_ClientViewed, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientViewed, this.cipherId);
}
this.previousCipherId = this.cipherId;
this.reprompt = this.cipher.reprompt !== CipherRepromptType.None;
@@ -489,14 +489,20 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showPassword = !this.showPassword;
document.getElementById("loginPassword").focus();
if (this.editMode && this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledPasswordVisible,
this.cipherId
);
}
}
async toggleCardNumber() {
this.showCardNumber = !this.showCardNumber;
if (this.showCardNumber) {
this.eventService.collect(EventType.Cipher_ClientToggledCardNumberVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardNumberVisible,
this.cipherId
);
}
}
@@ -504,7 +510,10 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.showCardCode = !this.showCardCode;
document.getElementById("cardCode").focus();
if (this.editMode && this.showCardCode) {
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardCodeVisible,
this.cipherId
);
}
}

View File

@@ -3,7 +3,7 @@ import { UntypedFormBuilder, Validators } from "@angular/forms";
import { merge, takeUntil, Subject, startWith } from "rxjs";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { ExportService } from "@bitwarden/common/abstractions/export.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -45,7 +45,7 @@ export class ExportComponent implements OnInit, OnDestroy {
protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService,
protected exportService: ExportService,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
private policyService: PolicyService,
protected win: Window,
private logService: LogService,
@@ -180,7 +180,7 @@ export class ExportComponent implements OnInit, OnDestroy {
}
protected async collectEvent(): Promise<void> {
await this.eventService.collect(EventType.User_ClientExportedVault);
await this.eventCollectionService.collect(EventType.User_ClientExportedVault);
}
get format() {

View File

@@ -1,6 +1,6 @@
import { Directive, Input } from "@angular/core";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventType } from "@bitwarden/common/enums/eventType";
import { FieldType } from "@bitwarden/common/enums/fieldType";
import { CipherView } from "@bitwarden/common/models/view/cipher.view";
@@ -14,7 +14,7 @@ export class ViewCustomFieldsComponent {
fieldType = FieldType;
constructor(private eventService: EventService) {}
constructor(private eventCollectionService: EventCollectionService) {}
async toggleFieldValue(field: FieldView) {
if (!(await this.promptPassword())) {
@@ -25,7 +25,10 @@ export class ViewCustomFieldsComponent {
f.showValue = !f.showValue;
f.showCount = false;
if (f.showValue) {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipher.id);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipher.id
);
}
}

View File

@@ -15,7 +15,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
import { CipherService } from "@bitwarden/common/abstractions/cipher.service";
import { CryptoService } from "@bitwarden/common/abstractions/crypto.service";
import { EventService } from "@bitwarden/common/abstractions/event.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service";
import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction";
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
@@ -80,7 +80,7 @@ export class ViewComponent implements OnDestroy, OnInit {
protected broadcasterService: BroadcasterService,
protected ngZone: NgZone,
protected changeDetectorRef: ChangeDetectorRef,
protected eventService: EventService,
protected eventCollectionService: EventCollectionService,
protected apiService: ApiService,
protected passwordRepromptService: PasswordRepromptService,
private logService: LogService,
@@ -138,7 +138,7 @@ export class ViewComponent implements OnDestroy, OnInit {
}
if (this.previousCipherId !== this.cipherId) {
this.eventService.collect(EventType.Cipher_ClientViewed, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientViewed, this.cipherId);
}
this.previousCipherId = this.cipherId;
}
@@ -238,7 +238,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showPassword = !this.showPassword;
this.showPasswordCount = false;
if (this.showPassword) {
this.eventService.collect(EventType.Cipher_ClientToggledPasswordVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledPasswordVisible,
this.cipherId
);
}
}
@@ -257,7 +260,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showCardNumber = !this.showCardNumber;
if (this.showCardNumber) {
this.eventService.collect(EventType.Cipher_ClientToggledCardNumberVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardNumberVisible,
this.cipherId
);
}
}
@@ -268,7 +274,10 @@ export class ViewComponent implements OnDestroy, OnInit {
this.showCardCode = !this.showCardCode;
if (this.showCardCode) {
this.eventService.collect(EventType.Cipher_ClientToggledCardCodeVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledCardCodeVisible,
this.cipherId
);
}
}
@@ -328,11 +337,14 @@ export class ViewComponent implements OnDestroy, OnInit {
);
if (typeI18nKey === "password") {
this.eventService.collect(EventType.Cipher_ClientToggledHiddenFieldVisible, this.cipherId);
this.eventCollectionService.collect(
EventType.Cipher_ClientToggledHiddenFieldVisible,
this.cipherId
);
} else if (typeI18nKey === "securityCode") {
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedCardCode, this.cipherId);
} else if (aType === "H_Field") {
this.eventService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
this.eventCollectionService.collect(EventType.Cipher_ClientCopiedHiddenField, this.cipherId);
}
}

View File

@@ -19,7 +19,8 @@ import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abs
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service";
import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service";
import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/common/abstractions/environment.service";
import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service";
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 { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service";
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service";
import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction";
@@ -85,7 +86,8 @@ import { CryptoService } from "@bitwarden/common/services/crypto.service";
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/services/cryptography/multithread-encrypt.service.implementation";
import { EnvironmentService } from "@bitwarden/common/services/environment.service";
import { EventService } from "@bitwarden/common/services/event.service";
import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service";
import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service";
import { ExportService } from "@bitwarden/common/services/export.service";
import { FileUploadService } from "@bitwarden/common/services/fileUpload.service";
import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service";
@@ -457,14 +459,18 @@ import { AbstractThemingService } from "./theming/theming.service.abstraction";
deps: [CryptoFunctionServiceAbstraction, LogService, LOG_MAC_FAILURES],
},
{
provide: EventServiceAbstraction,
useClass: EventService,
provide: EventUploadServiceAbstraction,
useClass: EventUploadService,
deps: [ApiServiceAbstraction, StateServiceAbstraction, LogService],
},
{
provide: EventCollectionServiceAbstraction,
useClass: EventCollectionService,
deps: [
ApiServiceAbstraction,
CipherServiceAbstraction,
StateServiceAbstraction,
LogService,
OrganizationServiceAbstraction,
EventUploadServiceAbstraction,
],
},
{

View File

@@ -1,12 +0,0 @@
import { EventType } from "../enums/eventType";
export abstract class EventService {
collect: (
eventType: EventType,
cipherId?: string,
uploadImmediately?: boolean,
organizationId?: string
) => Promise<any>;
uploadEvents: (userId?: string) => Promise<any>;
clearEvents: (userId?: string) => Promise<any>;
}

View File

@@ -0,0 +1,10 @@
import { EventType } from "../../enums/eventType";
export abstract class EventCollectionService {
collect: (
eventType: EventType,
cipherId?: string,
uploadImmediately?: boolean,
organizationId?: string
) => Promise<any>;
}

View File

@@ -0,0 +1,3 @@
export abstract class EventUploadService {
uploadEvents: (userId?: string) => Promise<void>;
}

View File

@@ -1,107 +0,0 @@
import { ApiService } from "../abstractions/api.service";
import { CipherService } from "../abstractions/cipher.service";
import { EventService as EventServiceAbstraction } from "../abstractions/event.service";
import { LogService } from "../abstractions/log.service";
import { OrganizationService } from "../abstractions/organization/organization.service.abstraction";
import { StateService } from "../abstractions/state.service";
import { EventType } from "../enums/eventType";
import { EventData } from "../models/data/event.data";
import { EventRequest } from "../models/request/event.request";
export class EventService implements EventServiceAbstraction {
private inited = false;
constructor(
private apiService: ApiService,
private cipherService: CipherService,
private stateService: StateService,
private logService: LogService,
private organizationService: OrganizationService
) {}
init(checkOnInterval: boolean) {
if (this.inited) {
return;
}
this.inited = true;
if (checkOnInterval) {
this.uploadEvents();
setInterval(() => this.uploadEvents(), 60 * 1000); // check every 60 seconds
}
}
async collect(
eventType: EventType,
cipherId: string = null,
uploadImmediately = false,
organizationId: string = null
): Promise<any> {
const authed = await this.stateService.getIsAuthenticated();
if (!authed) {
return;
}
const organizations = await this.organizationService.getAll();
if (organizations == null) {
return;
}
const orgIds = new Set<string>(organizations.filter((o) => o.useEvents).map((o) => o.id));
if (orgIds.size === 0) {
return;
}
if (cipherId != null) {
const cipher = await this.cipherService.get(cipherId);
if (cipher == null || cipher.organizationId == null || !orgIds.has(cipher.organizationId)) {
return;
}
}
if (organizationId != null) {
if (!orgIds.has(organizationId)) {
return;
}
}
let eventCollection = await this.stateService.getEventCollection();
if (eventCollection == null) {
eventCollection = [];
}
const event = new EventData();
event.type = eventType;
event.cipherId = cipherId;
event.date = new Date().toISOString();
event.organizationId = organizationId;
eventCollection.push(event);
await this.stateService.setEventCollection(eventCollection);
if (uploadImmediately) {
await this.uploadEvents();
}
}
async uploadEvents(userId?: string): Promise<any> {
const authed = await this.stateService.getIsAuthenticated({ userId: userId });
if (!authed) {
return;
}
const eventCollection = await this.stateService.getEventCollection({ userId: userId });
if (eventCollection == null || eventCollection.length === 0) {
return;
}
const request = eventCollection.map((e) => {
const req = new EventRequest();
req.type = e.type;
req.cipherId = e.cipherId;
req.date = e.date;
req.organizationId = e.organizationId;
return req;
});
try {
await this.apiService.postEventsCollect(request);
this.clearEvents(userId);
} catch (e) {
this.logService.error(e);
}
}
async clearEvents(userId?: string): Promise<any> {
await this.stateService.setEventCollection(null, { userId: userId });
}
}

View File

@@ -0,0 +1,61 @@
import { CipherService } from "../../abstractions/cipher.service";
import { EventCollectionService as EventCollectionServiceAbstraction } from "../../abstractions/event/event-collection.service";
import { EventUploadService } from "../../abstractions/event/event-upload.service";
import { OrganizationService } from "../../abstractions/organization/organization.service.abstraction";
import { StateService } from "../../abstractions/state.service";
import { EventType } from "../../enums/eventType";
import { EventData } from "../../models/data/event.data";
export class EventCollectionService implements EventCollectionServiceAbstraction {
constructor(
private cipherService: CipherService,
private stateService: StateService,
private organizationService: OrganizationService,
private eventUploadService: EventUploadService
) {}
async collect(
eventType: EventType,
cipherId: string = null,
uploadImmediately = false,
organizationId: string = null
): Promise<any> {
const authed = await this.stateService.getIsAuthenticated();
if (!authed) {
return;
}
const organizations = await this.organizationService.getAll();
if (organizations == null) {
return;
}
const orgIds = new Set<string>(organizations.filter((o) => o.useEvents).map((o) => o.id));
if (orgIds.size === 0) {
return;
}
if (cipherId != null) {
const cipher = await this.cipherService.get(cipherId);
if (cipher == null || cipher.organizationId == null || !orgIds.has(cipher.organizationId)) {
return;
}
}
if (organizationId != null) {
if (!orgIds.has(organizationId)) {
return;
}
}
let eventCollection = await this.stateService.getEventCollection();
if (eventCollection == null) {
eventCollection = [];
}
const event = new EventData();
event.type = eventType;
event.cipherId = cipherId;
event.date = new Date().toISOString();
event.organizationId = organizationId;
eventCollection.push(event);
await this.stateService.setEventCollection(eventCollection);
if (uploadImmediately) {
await this.eventUploadService.uploadEvents();
}
}
}

View File

@@ -0,0 +1,55 @@
import { ApiService } from "../../abstractions/api.service";
import { EventUploadService as EventUploadServiceAbstraction } from "../../abstractions/event/event-upload.service";
import { LogService } from "../../abstractions/log.service";
import { StateService } from "../../abstractions/state.service";
import { EventRequest } from "../../models/request/event.request";
export class EventUploadService implements EventUploadServiceAbstraction {
private inited = false;
constructor(
private apiService: ApiService,
private stateService: StateService,
private logService: LogService
) {}
init(checkOnInterval: boolean) {
if (this.inited) {
return;
}
this.inited = true;
if (checkOnInterval) {
this.uploadEvents();
setInterval(() => this.uploadEvents(), 60 * 1000); // check every 60 seconds
}
}
async uploadEvents(userId?: string): Promise<void> {
const authed = await this.stateService.getIsAuthenticated({ userId: userId });
if (!authed) {
return;
}
const eventCollection = await this.stateService.getEventCollection({ userId: userId });
if (eventCollection == null || eventCollection.length === 0) {
return;
}
const request = eventCollection.map((e) => {
const req = new EventRequest();
req.type = e.type;
req.cipherId = e.cipherId;
req.date = e.date;
req.organizationId = e.organizationId;
return req;
});
try {
await this.apiService.postEventsCollect(request);
this.clearEvents(userId);
} catch (e) {
this.logService.error(e);
}
}
private async clearEvents(userId?: string): Promise<any> {
await this.stateService.setEventCollection(null, { userId: userId });
}
}