2018-07-07 05:08:10 +02:00
|
|
|
import { Injectable } from '@angular/core';
|
|
|
|
|
|
|
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
|
|
|
|
2018-07-09 17:47:57 +02:00
|
|
|
import { DeviceType } from 'jslib/enums/deviceType';
|
|
|
|
import { EventType } from 'jslib/enums/eventType';
|
|
|
|
|
|
|
|
import { EventResponse } from 'jslib/models/response/eventResponse';
|
|
|
|
|
2018-07-07 05:08:10 +02:00
|
|
|
@Injectable()
|
|
|
|
export class EventService {
|
|
|
|
constructor(private i18nService: I18nService) { }
|
|
|
|
|
|
|
|
getDefaultDateFilters() {
|
|
|
|
const d = new Date();
|
|
|
|
const end = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59);
|
|
|
|
d.setDate(d.getDate() - 30);
|
|
|
|
const start = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0);
|
|
|
|
return [this.toDateTimeLocalString(start), this.toDateTimeLocalString(end)];
|
|
|
|
}
|
|
|
|
|
|
|
|
formatDateFilters(filterStart: string, filterEnd: string) {
|
|
|
|
const start: Date = new Date(filterStart);
|
|
|
|
const end: Date = new Date(filterEnd + ':59.999');
|
|
|
|
if (isNaN(start.getTime()) || isNaN(end.getTime()) || end < start) {
|
|
|
|
throw new Error('Invalid date range.');
|
|
|
|
}
|
|
|
|
return [start.toISOString(), end.toISOString()];
|
|
|
|
}
|
|
|
|
|
2018-07-09 17:47:57 +02:00
|
|
|
getEventInfo(ev: EventResponse, options = new EventOptions()): EventInfo {
|
|
|
|
const appInfo = this.getAppInfo(ev.deviceType);
|
|
|
|
return {
|
|
|
|
message: this.getEventMessage(ev, options),
|
|
|
|
appIcon: appInfo[0],
|
|
|
|
appName: appInfo[1],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private getEventMessage(ev: EventResponse, options: EventOptions) {
|
|
|
|
let msg = '';
|
|
|
|
switch (ev.type) {
|
|
|
|
// User
|
|
|
|
case EventType.User_LoggedIn:
|
|
|
|
msg = this.i18nService.t('loggedIn');
|
|
|
|
break;
|
|
|
|
case EventType.User_ChangedPassword:
|
|
|
|
msg = this.i18nService.t('changedPassword');
|
|
|
|
break;
|
2018-10-09 22:01:00 +02:00
|
|
|
case EventType.User_Updated2fa:
|
|
|
|
msg = this.i18nService.t('enabledUpdated2fa');
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.User_Disabled2fa:
|
|
|
|
msg = this.i18nService.t('disabled2fa');
|
|
|
|
break;
|
|
|
|
case EventType.User_Recovered2fa:
|
|
|
|
msg = this.i18nService.t('recovered2fa');
|
|
|
|
break;
|
|
|
|
case EventType.User_FailedLogIn:
|
|
|
|
msg = this.i18nService.t('failedLogin');
|
|
|
|
break;
|
|
|
|
case EventType.User_FailedLogIn2fa:
|
|
|
|
msg = this.i18nService.t('failedLogin2fa');
|
|
|
|
break;
|
2019-07-12 04:03:12 +02:00
|
|
|
case EventType.User_ClientExportedVault:
|
|
|
|
msg = this.i18nService.t('exportedVault');
|
|
|
|
break;
|
2018-07-09 17:47:57 +02:00
|
|
|
// Cipher
|
|
|
|
case EventType.Cipher_Created:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('createdItemId', this.formatCipherId(ev, options));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Cipher_Updated:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('editedItemId', this.formatCipherId(ev, options));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Cipher_Deleted:
|
2020-04-08 22:48:30 +02:00
|
|
|
msg = this.i18nService.t('permanentlyDeletedItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_SoftDeleted:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('deletedItemId', this.formatCipherId(ev, options));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
2020-04-08 22:48:30 +02:00
|
|
|
case EventType.Cipher_Restored:
|
|
|
|
msg = this.i18nService.t('restoredItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
2018-07-09 17:47:57 +02:00
|
|
|
case EventType.Cipher_AttachmentCreated:
|
|
|
|
msg = this.i18nService.t('createdAttachmentForItem', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_AttachmentDeleted:
|
|
|
|
msg = this.i18nService.t('deletedAttachmentForItem', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_Shared:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('sharedItemId', this.formatCipherId(ev, options));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
2019-07-12 04:03:12 +02:00
|
|
|
case EventType.Cipher_ClientViewed:
|
|
|
|
msg = this.i18nService.t('viewedItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientToggledPasswordVisible:
|
|
|
|
msg = this.i18nService.t('viewedPasswordItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientToggledHiddenFieldVisible:
|
|
|
|
msg = this.i18nService.t('viewedHiddenFieldItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientToggledCardCodeVisible:
|
|
|
|
msg = this.i18nService.t('viewedSecurityCodeItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientCopiedHiddenField:
|
|
|
|
msg = this.i18nService.t('copiedHiddenFieldItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientCopiedPassword:
|
|
|
|
msg = this.i18nService.t('copiedPasswordItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientCopiedCardCode:
|
|
|
|
msg = this.i18nService.t('copiedSecurityCodeItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
case EventType.Cipher_ClientAutofilled:
|
|
|
|
msg = this.i18nService.t('autofilledItemId', this.formatCipherId(ev, options));
|
|
|
|
break;
|
2018-07-09 17:47:57 +02:00
|
|
|
case EventType.Cipher_UpdatedCollections:
|
|
|
|
msg = this.i18nService.t('editedCollectionsForItem', this.formatCipherId(ev, options));
|
|
|
|
break;
|
|
|
|
// Collection
|
|
|
|
case EventType.Collection_Created:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('createdCollectionId', this.formatCollectionId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Collection_Updated:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('editedCollectionId', this.formatCollectionId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Collection_Deleted:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('deletedCollectionId', this.formatCollectionId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
// Group
|
|
|
|
case EventType.Group_Created:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('createdGroupId', this.formatGroupId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Group_Updated:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('editedGroupId', this.formatGroupId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.Group_Deleted:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('deletedGroupId', this.formatGroupId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
// Org user
|
|
|
|
case EventType.OrganizationUser_Invited:
|
2018-07-10 14:47:34 +02:00
|
|
|
msg = this.i18nService.t('invitedUserId', this.formatOrgUserId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_Confirmed:
|
2018-07-10 14:47:34 +02:00
|
|
|
msg = this.i18nService.t('confirmedUserId', this.formatOrgUserId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_Updated:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('editedUserId', this.formatOrgUserId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_Removed:
|
2018-07-10 14:39:05 +02:00
|
|
|
msg = this.i18nService.t('removedUserId', this.formatOrgUserId(ev));
|
2018-07-09 17:47:57 +02:00
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_UpdatedGroups:
|
|
|
|
msg = this.i18nService.t('editedGroupsForUser', this.formatOrgUserId(ev));
|
|
|
|
break;
|
2020-12-17 01:29:19 +01:00
|
|
|
case EventType.OrganizationUser_UnlinkedSso:
|
2020-12-22 17:28:58 +01:00
|
|
|
msg = this.i18nService.t('unlinkedSsoUser', this.formatOrgUserId(ev));
|
2021-04-05 16:48:46 +02:00
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_ResetPassword_Enroll:
|
|
|
|
msg = this.i18nService.t('eventEnrollPasswordReset', this.formatOrgUserId(ev));
|
|
|
|
break;
|
|
|
|
case EventType.OrganizationUser_ResetPassword_Withdraw:
|
|
|
|
msg = this.i18nService.t('eventWithdrawPasswordReset', this.formatOrgUserId(ev));
|
|
|
|
break;
|
2018-07-09 17:47:57 +02:00
|
|
|
// Org
|
|
|
|
case EventType.Organization_Updated:
|
|
|
|
msg = this.i18nService.t('editedOrgSettings');
|
|
|
|
break;
|
2018-09-25 15:12:24 +02:00
|
|
|
case EventType.Organization_PurgedVault:
|
|
|
|
msg = this.i18nService.t('purgedOrganizationVault');
|
|
|
|
break;
|
2019-07-12 23:15:40 +02:00
|
|
|
/*
|
|
|
|
case EventType.Organization_ClientExportedVault:
|
|
|
|
msg = this.i18nService.t('exportedOrganizationVault');
|
|
|
|
break;
|
|
|
|
*/
|
2020-12-08 20:24:59 +01:00
|
|
|
// Policies
|
|
|
|
case EventType.Policy_Updated:
|
|
|
|
msg = this.i18nService.t('modifiedPolicy', this.formatPolicyId(ev));
|
|
|
|
break;
|
|
|
|
|
2018-07-09 17:47:57 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return msg === '' ? null : msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getAppInfo(deviceType: DeviceType): [string, string] {
|
|
|
|
switch (deviceType) {
|
|
|
|
case DeviceType.Android:
|
|
|
|
return ['fa-android', this.i18nService.t('mobile') + ' - Android'];
|
|
|
|
case DeviceType.iOS:
|
|
|
|
return ['fa-apple', this.i18nService.t('mobile') + ' - iOS'];
|
|
|
|
case DeviceType.UWP:
|
|
|
|
return ['fa-windows', this.i18nService.t('mobile') + ' - Windows'];
|
|
|
|
case DeviceType.ChromeExtension:
|
|
|
|
return ['fa-chrome', this.i18nService.t('extension') + ' - Chrome'];
|
|
|
|
case DeviceType.FirefoxExtension:
|
|
|
|
return ['fa-firefox', this.i18nService.t('extension') + ' - Firefox'];
|
|
|
|
case DeviceType.OperaExtension:
|
|
|
|
return ['fa-opera', this.i18nService.t('extension') + ' - Opera'];
|
|
|
|
case DeviceType.EdgeExtension:
|
|
|
|
return ['fa-edge', this.i18nService.t('extension') + ' - Edge'];
|
|
|
|
case DeviceType.VivaldiExtension:
|
|
|
|
return ['fa-puzzle-piece', this.i18nService.t('extension') + ' - Vivaldi'];
|
|
|
|
case DeviceType.SafariExtension:
|
|
|
|
return ['fa-safari', this.i18nService.t('extension') + ' - Safari'];
|
|
|
|
case DeviceType.WindowsDesktop:
|
|
|
|
return ['fa-windows', this.i18nService.t('desktop') + ' - Windows'];
|
|
|
|
case DeviceType.MacOsDesktop:
|
|
|
|
return ['fa-apple', this.i18nService.t('desktop') + ' - macOS'];
|
|
|
|
case DeviceType.LinuxDesktop:
|
|
|
|
return ['fa-linux', this.i18nService.t('desktop') + ' - Linux'];
|
|
|
|
case DeviceType.ChromeBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Chrome'];
|
|
|
|
case DeviceType.FirefoxBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Firefox'];
|
|
|
|
case DeviceType.OperaBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Opera'];
|
|
|
|
case DeviceType.SafariBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Safari'];
|
|
|
|
case DeviceType.VivaldiBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Vivaldi'];
|
|
|
|
case DeviceType.EdgeBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - Edge'];
|
|
|
|
case DeviceType.IEBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - IE'];
|
|
|
|
case DeviceType.UnknownBrowser:
|
|
|
|
return ['fa-globe', this.i18nService.t('webVault') + ' - ' + this.i18nService.t('unknown')];
|
|
|
|
default:
|
|
|
|
return ['fa-globe', this.i18nService.t('unknown')];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private formatCipherId(ev: EventResponse, options: EventOptions) {
|
|
|
|
const shortId = this.getShortId(ev.cipherId);
|
|
|
|
if (ev.organizationId == null || !options.cipherInfo) {
|
|
|
|
return '<code>' + shortId + '</code>';
|
|
|
|
}
|
|
|
|
const a = this.makeAnchor(shortId);
|
|
|
|
a.setAttribute('href', '#/organizations/' + ev.organizationId + '/vault?search=' + shortId +
|
|
|
|
'&viewEvents=' + ev.cipherId);
|
|
|
|
return a.outerHTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
private formatGroupId(ev: EventResponse) {
|
|
|
|
const shortId = this.getShortId(ev.groupId);
|
|
|
|
const a = this.makeAnchor(shortId);
|
|
|
|
a.setAttribute('href', '#/organizations/' + ev.organizationId + '/manage/groups?search=' + shortId);
|
|
|
|
return a.outerHTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
private formatCollectionId(ev: EventResponse) {
|
|
|
|
const shortId = this.getShortId(ev.collectionId);
|
|
|
|
const a = this.makeAnchor(shortId);
|
|
|
|
a.setAttribute('href', '#/organizations/' + ev.organizationId + '/manage/collections?search=' + shortId);
|
|
|
|
return a.outerHTML;
|
|
|
|
}
|
|
|
|
|
|
|
|
private formatOrgUserId(ev: EventResponse) {
|
|
|
|
const shortId = this.getShortId(ev.organizationUserId);
|
|
|
|
const a = this.makeAnchor(shortId);
|
2018-07-11 21:44:40 +02:00
|
|
|
a.setAttribute('href', '#/organizations/' + ev.organizationId + '/manage/people?search=' + shortId +
|
|
|
|
'&viewEvents=' + ev.organizationUserId);
|
2018-07-09 17:47:57 +02:00
|
|
|
return a.outerHTML;
|
|
|
|
}
|
|
|
|
|
2020-12-08 20:24:59 +01:00
|
|
|
private formatPolicyId(ev: EventResponse) {
|
|
|
|
const shortId = this.getShortId(ev.policyId);
|
|
|
|
const a = this.makeAnchor(shortId);
|
|
|
|
a.setAttribute('href', '#/organizations/' + ev.organizationId + '/manage/policies?policyId=' + ev.policyId);
|
|
|
|
return a.outerHTML;
|
|
|
|
}
|
|
|
|
|
2018-07-09 17:47:57 +02:00
|
|
|
private makeAnchor(shortId: string) {
|
|
|
|
const a = document.createElement('a');
|
|
|
|
a.title = this.i18nService.t('view');
|
|
|
|
a.innerHTML = '<code>' + shortId + '</code>';
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
private getShortId(id: string) {
|
|
|
|
return id.substring(0, 8);
|
|
|
|
}
|
|
|
|
|
2018-07-07 05:08:10 +02:00
|
|
|
private toDateTimeLocalString(date: Date) {
|
|
|
|
return date.getFullYear() +
|
|
|
|
'-' + this.pad(date.getMonth() + 1) +
|
|
|
|
'-' + this.pad(date.getDate()) +
|
|
|
|
'T' + this.pad(date.getHours()) +
|
|
|
|
':' + this.pad(date.getMinutes());
|
|
|
|
}
|
|
|
|
|
|
|
|
private pad(num: number) {
|
|
|
|
const norm = Math.floor(Math.abs(num));
|
|
|
|
return (norm < 10 ? '0' : '') + norm;
|
|
|
|
}
|
|
|
|
}
|
2018-07-09 17:47:57 +02:00
|
|
|
|
|
|
|
export class EventInfo {
|
|
|
|
message: string;
|
|
|
|
appIcon: string;
|
|
|
|
appName: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class EventOptions {
|
|
|
|
cipherInfo = true;
|
|
|
|
}
|