From c10ade46c0a5cfd6951086d02db20b2d9528c2e1 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Fri, 12 Jan 2018 10:05:30 -0500 Subject: [PATCH] refactor analytics to ts --- src/background.ts | 3 - src/background/main.background.ts | 3 + src/browser/browserApi.ts | 10 +++ src/popup/app/app.js | 4 +- src/scripts/analytics.js | 86 ---------------------- src/scripts/analytics.ts | 118 ++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+), 90 deletions(-) delete mode 100644 src/scripts/analytics.js create mode 100644 src/scripts/analytics.ts diff --git a/src/background.ts b/src/background.ts index 0c7fc13d2f..e989cef5d9 100644 --- a/src/background.ts +++ b/src/background.ts @@ -3,7 +3,4 @@ import MainBackground from './background/main.background'; const bitwardenIsBackground = (window as any).bitwardenIsBackground = true; const bitwardenMain = (window as any).bitwardenMain = new MainBackground(); -// tslint:disable-next-line:no-var-requires -require('./scripts/analytics.js'); - bitwardenMain.bootstrap(); diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 1df9442425..7588494ad2 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -41,6 +41,8 @@ import { UtilsService as UtilsServiceAbstraction, } from 'jslib/abstractions'; +import Analytics from '../scripts/analytics'; + import BrowserApi from '../browser/browserApi'; import CommandsBackground from './commands.background'; @@ -157,6 +159,7 @@ export default class MainBackground { } async bootstrap() { + await new Analytics(window).init(); this.containerService.attachToWindow(window); if (!this.isSafari) { diff --git a/src/browser/browserApi.ts b/src/browser/browserApi.ts index 08e350076b..3c1722b8a2 100644 --- a/src/browser/browserApi.ts +++ b/src/browser/browserApi.ts @@ -62,4 +62,14 @@ export default class BrowserApi { return null; } } + + static getApplicationVersion(): any { + if (BrowserApi.isChromeApi) { + return chrome.runtime.getManifest().version; + } else if (BrowserApi.isSafariApi) { + return 0; // TODO + } else { + return null; + } + } } diff --git a/src/popup/app/app.js b/src/popup/app/app.js index 9979dfa92e..64ffa39ae1 100644 --- a/src/popup/app/app.js +++ b/src/popup/app/app.js @@ -13,13 +13,15 @@ require('angulartics'); require('angulartics-google-analytics'); require('ng-infinite-scroll'); -require('../../scripts/analytics.js'); require('../../scripts/duo.js'); require('../../scripts/u2f.js'); require('../less/libs.less'); require('../less/popup.less'); +import Analytics from '../../scripts/analytics'; +new Analytics(window).init(); // await? + import DirectivesModule from './directives/directives.module'; import ComponentsModule from './components/components.module'; import ToolsModule from './tools/tools.module'; diff --git a/src/scripts/analytics.js b/src/scripts/analytics.js deleted file mode 100644 index f44af5bdf0..0000000000 --- a/src/scripts/analytics.js +++ /dev/null @@ -1,86 +0,0 @@ -(function () { - var bgPage = chrome.extension.getBackgroundPage(); - if (!bgPage) { - return; - } - - var bgMain = bgPage.bitwardenMain; - if (!bgMain) { - return; - } - - var gaTrackingId = bgMain.platformUtilsService.analyticsId(); - var gaFunc = null; - var isFirefox = bgMain.platformUtilsService.isFirefox(); - - window.GoogleAnalyticsObject = 'ga'; - window[window.GoogleAnalyticsObject] = function (action, param1, param2, param3, param4) { - if (!gaFunc) { - return; - } - - chrome.storage.local.get('disableGa', function (obj) { - // Default for Firefox is disabled. - if ((isFirefox && obj.disableGa === undefined) || obj.disableGa) { - return; - } - - gaFunc(action, param1, param2, param3, param4); - }); - }; - - function gaTrackEvent(options) { - return '&t=event&ec=' + (options.eventCategory ? encodeURIComponent(options.eventCategory) : 'Event') + - '&ea=' + encodeURIComponent(options.eventAction) + - (options.eventLabel ? '&el=' + encodeURIComponent(options.eventLabel) : '') + - (options.eventValue ? '&ev=' + encodeURIComponent(options.eventValue) : '') + - (options.page ? '&dp=' + cleanPagePath(options.page) : ''); - } - - function gaTrackPageView(pagePath) { - return '&t=pageview&dp=' + cleanPagePath(pagePath); - } - - function cleanPagePath(pagePath) { - var paramIndex = pagePath.indexOf('?'); - if (paramIndex > -1) { - pagePath = pagePath.substring(0, paramIndex); - } - if (pagePath.indexOf('!/') === 0) { - pagePath = pagePath.substring(1); - } - return encodeURIComponent(pagePath); - } - - bgMain.appIdService.getAnonymousAppId().then(function (gaAnonAppId) { - gaFunc = function (action, param1, param2, param3, param4) { - if (action !== 'send' || !param1) { - return; - } - - var version = encodeURIComponent(chrome.runtime.getManifest().version); - var message = 'v=1&tid=' + gaTrackingId + '&cid=' + gaAnonAppId + '&cd1=' + version; - - if (param1 === 'pageview' && param2) { - message += gaTrackPageView(param2); - } - else if (typeof param1 === 'object' && param1.hitType === 'pageview') { - message += gaTrackPageView(param1.page); - } - else if (param1 === 'event' && param2) { - message += gaTrackEvent(param2); - } - else if (typeof param1 === 'object' && param1.hitType === 'event') { - message += gaTrackEvent(param1); - } - - var request = new XMLHttpRequest(); - request.open('POST', 'https://www.google-analytics.com/collect', true); - request.send(message); - }; - - if (typeof bitwardenIsBackground !== 'undefined') { - ga('send', 'pageview', '/background.html'); - } - }); -})(); diff --git a/src/scripts/analytics.ts b/src/scripts/analytics.ts new file mode 100644 index 0000000000..106646f77e --- /dev/null +++ b/src/scripts/analytics.ts @@ -0,0 +1,118 @@ +import BrowserApi from '../browser/browserApi'; + +import { AppIdService } from 'jslib/abstractions/appId.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; +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 gaFunc: Function = null; + private win: any; + private isBackground: boolean = false; + + constructor(win: Window) { + const bgPage = BrowserApi.getBackgroundPage(); + if (!bgPage) { + return; + } + + const bgMain = bgPage.bitwardenMain; + if (!bgMain) { + return; + } + + this.platformUtilsService = bgMain.platformUtilsService as PlatformUtilsService; + this.storageService = bgMain.storageService as StorageService; + this.appIdService = bgMain.appIdService as AppIdService; + + this.win = win; + this.isFirefox = this.platformUtilsService.isFirefox(); + this.gaTrackingId = this.platformUtilsService.analyticsId(); + this.isBackground = (typeof this.win.bitwardenIsBackground !== 'undefined'); + } + + async init() { + if (this.inited) { + throw new Error('Analytics already initialized.'); + } + + if (!this.platformUtilsService || !this.storageService || !this.appIdService) { + return; + } + + this.inited = true; + + this.win.GoogleAnalyticsObject = gaObj; + this.win[gaObj] = async (action: any, param1: any, param2: any, param3: any, param4: any) => { + if (!this.gaFunc) { + 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); + }; + + 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(BrowserApi.getApplicationVersion()); + 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'); + } + } + + private gaTrackEvent(options: any) { + return '&t=event&ec=' + (options.eventCategory ? encodeURIComponent(options.eventCategory) : 'Event') + + '&ea=' + encodeURIComponent(options.eventAction) + + (options.eventLabel ? '&el=' + encodeURIComponent(options.eventLabel) : '') + + (options.eventValue ? '&ev=' + encodeURIComponent(options.eventValue) : '') + + (options.page ? '&dp=' + this.cleanPagePath(options.page) : ''); + } + + private gaTrackPageView(pagePath: string) { + return '&t=pageview&dp=' + this.cleanPagePath(pagePath); + } + + private cleanPagePath(pagePath: string) { + const paramIndex = pagePath.indexOf('?'); + if (paramIndex > -1) { + pagePath = pagePath.substring(0, paramIndex); + } + if (pagePath.indexOf('!/') === 0) { + pagePath = pagePath.substring(1); + } + return encodeURIComponent(pagePath); + } +}