diff --git a/src/background.ts b/src/background.ts index fb96ade703..301fe1a289 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,8 +1,6 @@ import MainBackground from './background/main.background'; -const bitwardenIsBackground = (window as any).bitwardenIsBackground = true; const bitwardenMain = (window as any).bitwardenMain = new MainBackground(); - bitwardenMain.bootstrap().then(() => { // Finished bootstrapping }); diff --git a/src/background/commands.background.ts b/src/background/commands.background.ts index f1b37bd5bb..4236dee87c 100644 --- a/src/background/commands.background.ts +++ b/src/background/commands.background.ts @@ -1,5 +1,6 @@ import { BrowserApi } from '../browser/browserApi'; +import Analytics from '../scripts/analytics'; import MainBackground from './main.background'; import { @@ -16,7 +17,7 @@ export default class CommandsBackground { private isVivaldi: boolean; constructor(private main: MainBackground, private passwordGenerationService: PasswordGenerationService, - private platformUtilsService: PlatformUtilsService) { + private platformUtilsService: PlatformUtilsService, private analytics: Analytics) { this.isSafari = this.platformUtilsService.isSafari(); this.isEdge = this.platformUtilsService.isEdge(); this.isVivaldi = this.platformUtilsService.isVivaldi(); @@ -68,7 +69,7 @@ export default class CommandsBackground { UtilsService.copyToClipboard(password); this.passwordGenerationService.addHistory(password); - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Generated Password From Command', }); @@ -85,7 +86,7 @@ export default class CommandsBackground { this.main.collectPageDetailsForContentScript(tab, 'autofill_cmd'); - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Autofilled From Command', }); @@ -98,7 +99,7 @@ export default class CommandsBackground { } this.main.openPopup(); - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Opened Popup From Command', }); diff --git a/src/background/contextMenus.background.ts b/src/background/contextMenus.background.ts index 93ffbe6a20..0587fba5c3 100644 --- a/src/background/contextMenus.background.ts +++ b/src/background/contextMenus.background.ts @@ -1,5 +1,6 @@ import { BrowserApi } from '../browser/browserApi'; +import Analytics from '../scripts/analytics'; import MainBackground from './main.background'; import { @@ -13,7 +14,7 @@ export default class ContextMenusBackground { private contextMenus: any; constructor(private main: MainBackground, private cipherService: CipherService, - private passwordGenerationService: PasswordGenerationService) { + private passwordGenerationService: PasswordGenerationService, private analytics: Analytics) { this.contextMenus = chrome.contextMenus; } @@ -38,7 +39,7 @@ export default class ContextMenusBackground { UtilsService.copyToClipboard(password); this.passwordGenerationService.addHistory(password); - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Generated Password From Context Menu', }); @@ -61,19 +62,19 @@ export default class ContextMenusBackground { } if (info.parentMenuItemId === 'autofill') { - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Autofilled From Context Menu', }); await this.startAutofillPage(cipher); } else if (info.parentMenuItemId === 'copy-username') { - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Copied Username From Context Menu', }); UtilsService.copyToClipboard(cipher.login.username); } else if (info.parentMenuItemId === 'copy-password') { - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Copied Password From Context Menu', }); diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 271da2b126..b7b5310c32 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -85,6 +85,7 @@ export default class MainBackground { totpService: TotpServiceAbstraction; autofillService: AutofillServiceAbstraction; containerService: ContainerService; + analytics: Analytics; onUpdatedRan: boolean; onReplacedRan: boolean; @@ -139,6 +140,7 @@ export default class MainBackground { this.autofillService = new AutofillService(this.cipherService, this.tokenService, this.totpService, this.utilsService, this.platformUtilsService); this.containerService = new ContainerService(this.cryptoService, this.platformUtilsService); + this.analytics = new Analytics(window, this.platformUtilsService, this.storageService, this.appIdService); // Other fields this.isSafari = this.platformUtilsService.isSafari(); @@ -147,14 +149,14 @@ export default class MainBackground { // Background this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, - this.platformUtilsService, this.storageService, this.i18nService); + this.platformUtilsService, this.storageService, this.i18nService, this.analytics); this.tabsBackground = new TabsBackground(this, this.platformUtilsService); this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, - this.platformUtilsService); + this.platformUtilsService, this.analytics); if (!this.isSafari) { this.contextMenusBackground = new ContextMenusBackground(this, this.cipherService, - this.passwordGenerationService); + this.passwordGenerationService, this.analytics); this.idleBackground = new IdleBackground(this, this.lockService, this.storageService); this.webRequestBackground = new WebRequestBackground(this.platformUtilsService, this.cipherService); this.windowsBackground = new WindowsBackground(this); @@ -162,7 +164,7 @@ export default class MainBackground { } async bootstrap() { - await new Analytics(window).init(); + this.analytics.ga('send', 'pageview', '/background.html'); this.containerService.attachToWindow(window); await this.runtimeBackground.init(); diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 49af155511..3845c463dc 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -11,6 +11,7 @@ import { import { BrowserApi } from '../browser/browserApi'; +import Analytics from '../scripts/analytics'; import MainBackground from './main.background'; import { AutofillService } from '../services/abstractions/autofill.service'; @@ -24,7 +25,7 @@ export default class RuntimeBackground { constructor(private main: MainBackground, private autofillService: AutofillService, private cipherService: CipherService, private platformUtilsService: PlatformUtilsService, - private storageService: StorageService, private i18nService: any) { + private storageService: StorageService, private i18nService: any, private analytics: Analytics) { this.isSafari = this.platformUtilsService.isSafari(); this.runtime = this.isSafari ? safari.application : chrome.runtime; @@ -190,7 +191,7 @@ export default class RuntimeBackground { }); await this.cipherService.saveWithServer(cipher); - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'Added Login from Notification Bar', }); @@ -284,7 +285,7 @@ export default class RuntimeBackground { await this.reseedStorage(); } - (window as any).ga('send', { + this.analytics.ga('send', { hitType: 'event', eventAction: 'onInstalled ' + this.onInstalledReason, }); diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 64ffa39ae1..0c5c63e575 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -20,7 +20,7 @@ require('../less/libs.less'); require('../less/popup.less'); import Analytics from '../../scripts/analytics'; -new Analytics(window).init(); // await? +new Analytics(window); import DirectivesModule from './directives/directives.module'; import ComponentsModule from './components/components.module'; diff --git a/src/scripts/analytics.ts b/src/scripts/analytics.ts index 324b09bc2f..53e8e10f26 100644 --- a/src/scripts/analytics.ts +++ b/src/scripts/analytics.ts @@ -7,19 +7,13 @@ import { StorageService } from 'jslib/abstractions/storage.service'; const gaObj = 'ga'; export default class Analytics { - private inited: boolean = false; - private platformUtilsService: PlatformUtilsService; - private storageService: StorageService; - private appIdService: AppIdService; private gaTrackingId: string = null; private isFirefox = false; private isSafari = false; - private gaFunc: Function = null; - private win: any; - private isBackground: boolean = false; private appVersion: string = BrowserApi.getApplicationVersion(); - constructor(win: Window) { + constructor(win: Window, private platformUtilsService?: PlatformUtilsService, + private storageService?: StorageService, private appIdService?: AppIdService) { const bgPage = BrowserApi.getBackgroundPage(); if (!bgPage) { return; @@ -30,74 +24,58 @@ export default class Analytics { return; } - this.platformUtilsService = bgMain.platformUtilsService as PlatformUtilsService; - this.storageService = bgMain.storageService as StorageService; - this.appIdService = bgMain.appIdService as AppIdService; + if (platformUtilsService == null) { + this.platformUtilsService = bgMain.platformUtilsService as PlatformUtilsService; + } + if (storageService == null) { + this.storageService = bgMain.storageService as StorageService; + } + if (appIdService == null) { + this.appIdService = bgMain.appIdService as AppIdService; + } - this.win = win; this.isFirefox = this.platformUtilsService.isFirefox(); this.isSafari = this.platformUtilsService.isSafari(); this.gaTrackingId = this.platformUtilsService.analyticsId(); - this.isBackground = (typeof this.win.bitwardenIsBackground !== 'undefined'); + + (win as any).GoogleAnalyticsObject = gaObj; + (win as any)[gaObj] = async (action: string, param1: any, param2?: any) => { + await this.ga(action, param1, param2); + }; } - async init() { - if (this.inited) { - throw new Error('Analytics already initialized.'); - } - - if (!this.platformUtilsService || !this.storageService || !this.appIdService) { + async ga(action: string, param1: any, param2?: any) { + if (this.isSafari && safari.application.activeBrowserWindow.activeTab.private) { return; } - this.inited = true; + const disabled = await this.storageService.get('disableGa'); + // Default for Firefox is disabled. + if ((this.isFirefox && disabled == null) || disabled != null && disabled) { + return; + } - this.win.GoogleAnalyticsObject = gaObj; - this.win[gaObj] = async (action: any, param1: any, param2: any, param3: any, param4: any) => { - if (!this.gaFunc) { - return; - } - - if (this.isSafari && safari.application.activeBrowserWindow.activeTab.private) { - return; - } - - const disabled = await this.storageService.get('disableGa'); - // Default for Firefox is disabled. - if ((this.isFirefox && disabled == null) || disabled != null && disabled) { - return; - } - - this.gaFunc(action, param1, param2, param3, param4); - }; + if (action !== 'send' || !param1) { + return; + } const gaAnonAppId = await this.appIdService.getAnonymousAppId(); - this.gaFunc = (action: string, param1: any, param2: any, param3: any, param: any) => { - if (action !== 'send' || !param1) { - return; - } + const version = encodeURIComponent(this.appVersion); + let message = 'v=1&tid=' + this.gaTrackingId + '&cid=' + gaAnonAppId + '&cd1=' + version; - const version = encodeURIComponent(this.appVersion); - let message = 'v=1&tid=' + this.gaTrackingId + '&cid=' + gaAnonAppId + '&cd1=' + version; - - if (param1 === 'pageview' && param2) { - message += this.gaTrackPageView(param2); - } else if (typeof param1 === 'object' && param1.hitType === 'pageview') { - message += this.gaTrackPageView(param1.page); - } else if (param1 === 'event' && param2) { - message += this.gaTrackEvent(param2); - } else if (typeof param1 === 'object' && param1.hitType === 'event') { - message += this.gaTrackEvent(param1); - } - - const request = new XMLHttpRequest(); - request.open('POST', 'https://www.google-analytics.com/collect', true); - request.send(message); - }; - - if (this.isBackground) { - this.win[gaObj]('send', 'pageview', '/background.html'); + if (param1 === 'pageview' && param2) { + message += this.gaTrackPageView(param2); + } else if (typeof param1 === 'object' && param1.hitType === 'pageview') { + message += this.gaTrackPageView(param1.page); + } else if (param1 === 'event' && param2) { + message += this.gaTrackEvent(param2); + } else if (typeof param1 === 'object' && param1.hitType === 'event') { + message += this.gaTrackEvent(param1); } + + const request = new XMLHttpRequest(); + request.open('POST', 'https://www.google-analytics.com/collect', true); + request.send(message); } private gaTrackEvent(options: any) {