diff --git a/Firefox addon/Firefox addon.csproj b/Firefox addon/Firefox addon.csproj index 5807fd5..47b82fc 100644 --- a/Firefox addon/Firefox addon.csproj +++ b/Firefox addon/Firefox addon.csproj @@ -70,7 +70,6 @@ - @@ -129,7 +128,6 @@ - diff --git a/Firefox addon/KeeFox/chrome/content/KFUI.js b/Firefox addon/KeeFox/chrome/content/KFUI.js index 6643459..1795a02 100644 --- a/Firefox addon/KeeFox/chrome/content/KFUI.js +++ b/Firefox addon/KeeFox/chrome/content/KFUI.js @@ -135,7 +135,6 @@ keefox_win.UI = { } finally { browser.messageManager.sendAsyncMessage("keefox:cancelFormRecording"); - keefox_org.metricsManager.pushEvent("feature", "SaveNever"); browser.passwordSaver = null; } } @@ -201,14 +200,11 @@ keefox_win.UI = { saveData.getLogin(function (login, urlMergeMode) { if (saveData.update) { - keefox_org.metricsManager.pushEvent("feature", "updateLogin", - { "urlMergeMode": urlMergeMode, "filterState": filterState }); var result = keefox_org.updateLogin(login, saveData.oldLoginUUID, urlMergeMode, saveData.db); keefox_win.notificationManager.remove("password-save"); browser.passwordSaver.showUpdateSuccessNotification(); } else { - keefox_org.metricsManager.pushEvent("feature", "addLogin"); var result = keefox_org.addLogin(login, saveData.group, saveData.db); if (keefox_org._keeFoxExtension.prefs.getValue("rememberMRUGroup", false)) keefox_org._keeFoxExtension.prefs.setValue("MRUGroup-" + saveData.db, saveData.group); diff --git a/Firefox addon/KeeFox/chrome/content/PasswordSaver.js b/Firefox addon/KeeFox/chrome/content/PasswordSaver.js index 35f83fa..e584e73 100644 --- a/Firefox addon/KeeFox/chrome/content/PasswordSaver.js +++ b/Firefox addon/KeeFox/chrome/content/PasswordSaver.js @@ -437,7 +437,6 @@ keefox_win.PasswordSaver.prototype = abortAndLaunchManualEdit: function () { - keefox_org.metricsManager.pushEvent("feature", "abortAndLaunchManualEdit"); keefox_org.launchLoginEditor(this.saveData.oldLoginUUID, this.saveData.db); keefox_win.notificationManager.remove("password-save"); }, diff --git a/Firefox addon/KeeFox/chrome/content/UninstallHelper.js b/Firefox addon/KeeFox/chrome/content/UninstallHelper.js index f737d72..1712782 100644 --- a/Firefox addon/KeeFox/chrome/content/UninstallHelper.js +++ b/Firefox addon/KeeFox/chrome/content/UninstallHelper.js @@ -249,17 +249,6 @@ keefox_win.UninstallHelper.prototype = if (extraText.value.length > 0) extra = extraText.value.substr(0,15000); - keefox_org.metricsManager.pushEvent("uninstall", "feedback", - { - "connectState": this.connectState, - "setupState": this.setupState, - "tutorialProgress": this.tutorialProgress, - "varients": this.varients, - "reason": reason, - "extra": extra, - "disable": this.disabling - }, true); - let responseContainer = this.createResponseContainer(reason, this.connectState, this.setupState, this.tutorialProgress); responseContainer.classList.add("disabled"); diff --git a/Firefox addon/KeeFox/chrome/content/commonDialog.js b/Firefox addon/KeeFox/chrome/content/commonDialog.js index 469751c..71a095f 100644 --- a/Firefox addon/KeeFox/chrome/content/commonDialog.js +++ b/Firefox addon/KeeFox/chrome/content/commonDialog.js @@ -794,13 +794,11 @@ var keeFoxDialogManager = { if (autoFill) { // fill in the best matching login - keefox_org.metricsManager.pushEvent ("feature", "AutoFillDialog"); dialogFindLoginStorage.document.getElementById("loginTextbox").value = matchedLogins[bestMatch].username; dialogFindLoginStorage.document.getElementById("password1Textbox").value = matchedLogins[bestMatch].password; } if (autoSubmit || dialogFindLoginStorage.mustAutoSubmit) { - keefox_org.metricsManager.pushEvent ("feature", "AutoSubmitDialog"); Dialog.onButton0(); close(); } @@ -828,7 +826,6 @@ var keeFoxDialogManager = { fill : function (username, password) { - keefox_org.metricsManager.pushEvent ("feature", "MatchedSubmitDialog"); document.getElementById("loginTextbox").value = username; document.getElementById("password1Textbox").value = password; Dialog.onButton0(); diff --git a/Firefox addon/KeeFox/chrome/content/formsWin.js b/Firefox addon/KeeFox/chrome/content/formsWin.js index 79a3d56..585859e 100644 --- a/Firefox addon/KeeFox/chrome/content/formsWin.js +++ b/Firefox addon/KeeFox/chrome/content/formsWin.js @@ -86,9 +86,7 @@ keefox_win.loadAndAutoSubmit = function (button, ctrlClick, URL, uniqueID, dbFil keefox_win.Logger.debug("loading and auto submitting button " + button + ctrlClick + ":" + URL); else keefox_win.Logger.debug("loading and auto submitting button " + button + ctrlClick + "..."); - - keefox_org.metricsManager.pushEvent ("feature", "loadAndAutoSubmit"); - + var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); var newWindow = wm.getMostRecentWindow("navigator:browser") || diff --git a/Firefox addon/KeeFox/chrome/content/framescript/formsFillTab.js b/Firefox addon/KeeFox/chrome/content/framescript/formsFillTab.js index f4794ff..8fd2da3 100644 --- a/Firefox addon/KeeFox/chrome/content/framescript/formsFillTab.js +++ b/Firefox addon/KeeFox/chrome/content/framescript/formsFillTab.js @@ -720,7 +720,6 @@ var scanForOrphanedFields = function (doc) querySelectorAll: function() { return []; }, // Only use is for listing button elements submit: function() { return; } // Not possible to submit a pseudo form unless a button with custom JS has already been found }; - metricsManager.adjustAggregate("pseudoFormCreated", 1); } var tn = (new Date()).getTime(); @@ -1357,10 +1356,6 @@ var fillAndSubmit = function (automated, frameKey, formIndex, loginIndex) && matchResult.formReadyForSubmit) { Logger.info("Auto-submitting form..."); - if (automated) - metricsManager.pushEvent ("feature", "AutoSubmit"); - else - metricsManager.pushEvent ("feature", "ManualSubmit"); // Called "MatchedFill" previously (yes, I'm an idiot) submitForm(form); } else if (isMatchedLoginRequest) { @@ -1403,10 +1398,6 @@ var fillAndSubmit = function (automated, frameKey, formIndex, loginIndex) "logins": matchingLoginsFromAllFrames, "notifyUserOnSuccess": matchResult.notifyUserOnSuccess }); - metricsManager.pushEvent ("feature", "AutoFill"); - } else - { - metricsManager.pushEvent ("feature", "ManualFill"); // Called "MatchedSubmit" previously (yes, I'm an idiot) } } else { diff --git a/Firefox addon/KeeFox/chrome/content/framescript/keefoxTab.js b/Firefox addon/KeeFox/chrome/content/framescript/keefoxTab.js index e6c2bc9..27ea694 100644 --- a/Firefox addon/KeeFox/chrome/content/framescript/keefoxTab.js +++ b/Firefox addon/KeeFox/chrome/content/framescript/keefoxTab.js @@ -49,10 +49,9 @@ part of the global scope of this script from within a subscript so we work aroun this by passing in our main keefox_tab object for direct manipulation within the subscript. */ -// Load our logging, config and metrics subsystem proxies +// Load our logging and config subsystem proxies keefox_tab.scriptLoader.loadSubScript("chrome://keefox/content/framescript/proxies/logger.js", keefox_tab); keefox_tab.scriptLoader.loadSubScript("chrome://keefox/content/framescript/proxies/config.js", keefox_tab); -keefox_tab.scriptLoader.loadSubScript("chrome://keefox/content/framescript/proxies/metrics.js", keefox_tab); // Load our other javascript keefox_tab.scriptLoader.loadSubScript("chrome://keefox/content/shared/uriUtils.js", keefox_tab); diff --git a/Firefox addon/KeeFox/chrome/content/framescript/proxies/metrics.js b/Firefox addon/KeeFox/chrome/content/framescript/proxies/metrics.js deleted file mode 100644 index 5f47508..0000000 --- a/Firefox addon/KeeFox/chrome/content/framescript/proxies/metrics.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - KeeFox - Allows Firefox to communicate with KeePass (via the KeePassRPC KeePass plugin) - Copyright 2015 Chris Tomlinson - - This implements a proxy/stub so we can continue to call the metricsManager from the - frame script environment despite the real metricsManager living in chrome scope. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -"use strict"; -var metricsManager = { - pushEvent: function (category, name, params) // string, string, object of keys/vals - { - sendAsyncMessage("keefox:metrics-pushEvent", { - "category": category, - "name": name, - "params": params - }); - }, - - adjustAggregate: function (key, value) - { - sendAsyncMessage("keefox:metrics-adjustAggregate", { - "key": key, - "value": value - }); - } -}; \ No newline at end of file diff --git a/Firefox addon/KeeFox/chrome/content/install.js b/Firefox addon/KeeFox/chrome/content/install.js index 2e749c9..b26ed44 100644 --- a/Firefox addon/KeeFox/chrome/content/install.js +++ b/Firefox addon/KeeFox/chrome/content/install.js @@ -261,11 +261,6 @@ function prepareInstallPage() break; default: document.getElementById('ERRORInstallButtonMain').setAttribute('hidden', false); break; } - - // Record key parts of above info to help find problems and plan future KeeFox priorities - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "displayed", - { "installCase": installCase, - "downgrade": (args.downWarning == "1" && args.currentKPRPCv && args.newKPRPCv) }); } function installationError(error) @@ -282,7 +277,6 @@ function installationError(error) } showSection('restartInstallationOption'); resetInstallation(); - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "error", { "reason": error }); } function resetInstallation() @@ -296,8 +290,7 @@ function cancelCurrentDownload() persist.cancelSave(); showSection("ERRORInstallDownloadCanceled"); showSection('restartInstallationOption'); - resetInstallation(); - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "error", { "reason": "ERRORInstallDownloadCanceled" }); + resetInstallation(); } function hideInstallView() { @@ -324,7 +317,6 @@ function checksumFailed() { mainWindow.keefox_win.Logger.error("File checksum failed. Download corrupted?"); showSection("ERRORInstallDownloadChecksumFailed"); showSection('restartInstallationOption'); -mainWindow.keefox_org.metricsManager.pushEvent ("setup", "error", { "reason": "ERRORInstallDownloadChecksumFailed" }); } /******************** @@ -776,7 +768,6 @@ functions initiated by user choice in UI */ function setupExeInstall() { - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "installing", { "type": "dotNet.exe" }); hideInstallView(); showProgressView(); @@ -796,7 +787,6 @@ function setupExeInstall() */ function KPsetupExeSilentInstall() { - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "installing", { "type": "KeePass.exe-silent" }); hideInstallView(); showProgressView(); @@ -818,7 +808,6 @@ function KPsetupExeSilentInstall() */ function copyKRPCToKnownKPLocationInstall() { - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "installing", { "type": "copyKRPCToKnownKPLocation" }); hideInstallView(); let keePassLocation = mainWindow.keefox_org._keeFoxExtension.prefs @@ -856,7 +845,6 @@ function copyKRPCToKnownKPLocationInstall() */ function copyKPToSpecificLocationInstall() { - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "installing", { "type": "copyKPToSpecificLocation" }); // Cancel any automatically started downloads try { persist.cancelSave(); @@ -896,7 +884,6 @@ function copyKPToSpecificLocationInstall() */ function KPsetupExeInstall() { - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "installing", { "type": "KeePass.exe" }); hideInstallView(); showProgressView(); @@ -933,8 +920,6 @@ function launchAndConnectToKeePass() mainWindow.keefox_org.KeePassRPC.reconnectTimer.cancel(); mainWindow.keefox_org.KeePassRPC.reconnectVerySoon(); - - mainWindow.keefox_org.metricsManager.pushEvent ("setup", "success"); // launch KeePass and then try to connect to KeePassRPC mainWindow.keefox_org.launchKeePass(); diff --git a/Firefox addon/KeeFox/chrome/content/options.js b/Firefox addon/KeeFox/chrome/content/options.js index 31720cc..9e1e94b 100644 --- a/Firefox addon/KeeFox/chrome/content/options.js +++ b/Firefox addon/KeeFox/chrome/content/options.js @@ -20,7 +20,7 @@ function onLoad(){ 'lab-keePassRPCPort','lab-keePassRPCPortWarning','saveFavicons','lab-keePassDBToOpen','keePassDBToOpenBrowseButton', 'rememberMRUDB', 'rememberMRUGroup', 'lab-keePassRPCInstalledLocation', 'keePassRPCInstalledLocationBrowseButton', 'lab-keePassInstalledLocation', 'keePassInstalledLocationBrowseButton', 'lab-monoLocation','monoLocationBrowseButton','keePassRememberInstalledLocation','lab-keePassLocation', - 'desc-site-specific','desc-site-specific-savepass','desc-site-specific-link','desc-site-specific-savepass-link','desc-ConnSL','desc-ConnSL-ManualLink-link','desc-conn-sl-client','slc-Low','slc-Medium','slc-High','sls-Low','sls-Medium','sls-High','desc-conn-sl-client-detail','desc-conn-sl-server','desc-conn-sl-server-detail','desc-conn-sl-low','desc-conn-sl-high','desc-commands-intro','desc-metrics','desc-metrics-link','lab-sendUsageMetrics','lab-maxMatchedLoginsInMainPanel','notifyWhenEntryUpdated' + 'desc-site-specific','desc-site-specific-savepass','desc-site-specific-link','desc-site-specific-savepass-link','desc-ConnSL','desc-ConnSL-ManualLink-link','desc-conn-sl-client','slc-Low','slc-Medium','slc-High','sls-Low','sls-Medium','sls-High','desc-conn-sl-client-detail','desc-conn-sl-server','desc-conn-sl-server-detail','desc-conn-sl-low','desc-conn-sl-high','desc-commands-intro','lab-maxMatchedLoginsInMainPanel','notifyWhenEntryUpdated' ], ['title','label','tooltiptext','accesskey','value']); diff --git a/Firefox addon/KeeFox/chrome/content/options.xul b/Firefox addon/KeeFox/chrome/content/options.xul index 9efd742..95f96bd 100644 --- a/Firefox addon/KeeFox/chrome/content/options.xul +++ b/Firefox addon/KeeFox/chrome/content/options.xul @@ -66,7 +66,6 @@ - @@ -234,15 +233,6 @@ - %-KeeFox-pref-metrics-desc-% %-KeeFox-pref-metrics-link-% - - - diff --git a/Firefox addon/KeeFox/chrome/content/panel.js b/Firefox addon/KeeFox/chrome/content/panel.js index bfcf3aa..7d0021c 100644 --- a/Firefox addon/KeeFox/chrome/content/panel.js +++ b/Firefox addon/KeeFox/chrome/content/panel.js @@ -965,7 +965,6 @@ keefox_win.panel = { function (event) { keefox_org.utils.copyStringToClipboard(usernameField.value); keefox_win.panel.CustomizableUI.hidePanelForNode(keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); - keefox_org.metricsManager.adjustAggregate("copyUsername", 1); }); } @@ -977,7 +976,6 @@ keefox_win.panel = { function (event) { keefox_org.utils.copyStringToClipboard(passwordField.value); keefox_win.panel.CustomizableUI.hidePanelForNode(keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); - keefox_org.metricsManager.adjustAggregate("copyPassword", 1); }); } if (otherFieldCount > 1 || passwordFieldCount > 1) { @@ -999,7 +997,6 @@ keefox_win.panel = { function (event) { keefox_org.utils.copyStringToClipboard(o.value); keefox_win.panel.CustomizableUI.hidePanelForNode(keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); - keefox_org.metricsManager.adjustAggregate("copyOther", 1); }); } }); @@ -1015,7 +1012,6 @@ keefox_win.panel = { function (event) { keefox_org.utils.copyStringToClipboard(p.value); keefox_win.panel.CustomizableUI.hidePanelForNode(keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); - keefox_org.metricsManager.adjustAggregate("copyOther", 1); }); } }); @@ -1345,10 +1341,6 @@ keefox_win.panel = { { keefox_win.panel.addLoginContextActions(document, this.getAttribute('data-uuid'), this.getAttribute('data-fileName')); keefox_win.panel.displayContextMenu(keefox_win.panel._currentWindow.document, event, 'KeeFox-login-context'); - if (keefox_win.SearchFilter.getFilterState(document, 'PanelSection') == "all") - keefox_org.metricsManager.adjustAggregate("searchResultContextAll", 1); - else - keefox_org.metricsManager.adjustAggregate("searchResultContextCurrent", 1); } }, false); loginItem.addEventListener("keefoxCommand", function (event) { @@ -1361,20 +1353,12 @@ keefox_win.panel = { keefox_win.panel.CustomizableUI.hidePanelForNode( keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); keefox_win.panel.hideSubSections(); - if (keefox_win.SearchFilter.getFilterState(keefox_win.panel._currentWindow.document, 'PanelSection') == "all") - keefox_org.metricsManager.adjustAggregate("searchResultSelectedAll", 1); - else - keefox_org.metricsManager.adjustAggregate("searchResultSelectedCurrent", 1); }, false); loginItem.addEventListener("keefoxContext", function (event) { keefox_win.panel.addLoginContextActions(document, this.getAttribute('data-uuid'), this.getAttribute('data-fileName')); keefox_win.panel.displayContextMenu(keefox_win.panel._currentWindow.document, { target: event.detail.target, layerX: event.detail.layerX, layerY: event.detail.layerY }, 'KeeFox-login-context'); - if (keefox_win.SearchFilter.getFilterState(keefox_win.panel._currentWindow.document, 'PanelSection') == "all") - keefox_org.metricsManager.adjustAggregate("searchResultContextAll", 1); - else - keefox_org.metricsManager.adjustAggregate("searchResultContextCurrent", 1); }, false); loginItem.addEventListener("mouseenter", keefox_win.panel.onMouseEnterLogin, false); @@ -1417,13 +1401,6 @@ keefox_win.panel = { layerY: this.offsetTop + event.layerY }, 'KeeFox-login-context'); - keefox_org.metricsManager.adjustAggregate("loginContextButton", 1); - if (event.target.parentNode.parentNode.parentNode.id == "KeeFox-PanelSubSection-SearchResults") { - if (keefox_win.SearchFilter.getFilterState(keefox_win.panel._currentWindow.document, 'PanelSection') == "all") - keefox_org.metricsManager.adjustAggregate("searchResultContextAll", 1); - else - keefox_org.metricsManager.adjustAggregate("searchResultContextCurrent", 1); - } }, false); optionsMenuTrigger.setAttribute("id", "optionsMenuTrigger"); event.target.appendChild(optionsMenuTrigger); @@ -1734,7 +1711,6 @@ keefox_win.panel = { }, false); profileItem.addEventListener("keefoxCommand", function (event) { let kf = keefox_org; - kf.metricsManager.pushEvent ("feature", "generatePasswordFromProfile"); kf.generatePassword(this.textContent, keefox_win.panel._currentWindow.gLastValidURLStr); keefox_win.panel.CustomizableUI.hidePanelForNode( keefox_win.panel._currentWindow.document.getElementById('keefox-panelview')); @@ -1756,7 +1732,6 @@ keefox_win.panel = { generatePassword: function () { let kf = this._currentWindow.keefox_org; - kf.metricsManager.pushEvent ("feature", "generatePassword"); kf.generatePassword(null, this._currentWindow.gLastValidURLStr); }, diff --git a/Firefox addon/KeeFox/chrome/content/siteOptions.js b/Firefox addon/KeeFox/chrome/content/siteOptions.js index 087343d..b189b45 100644 --- a/Firefox addon/KeeFox/chrome/content/siteOptions.js +++ b/Firefox addon/KeeFox/chrome/content/siteOptions.js @@ -296,7 +296,6 @@ function addSite() var mainWindow = wm.getMostRecentWindow("navigator:browser") || wm.getMostRecentWindow("mail:3pane"); - mainWindow.keefox_org.metricsManager.pushEvent("feature", "SiteSpecificAdd"); configMan.setConfigForURL(newURL,{}); configMan.save(); go(newURL); diff --git a/Firefox addon/KeeFox/defaults/preferences/prefs.js b/Firefox addon/KeeFox/defaults/preferences/prefs.js index 98dd1ee..356e6a3 100644 --- a/Firefox addon/KeeFox/defaults/preferences/prefs.js +++ b/Firefox addon/KeeFox/defaults/preferences/prefs.js @@ -19,7 +19,6 @@ pref("extensions.keefox@chris.tomlinson.searchAllOpenDBs", true); pref("extensions.keefox@chris.tomlinson.listAllOpenDBs", true); pref("extensions.keefox@chris.tomlinson.connSLClient", 2); pref("extensions.keefox@chris.tomlinson.connSLServerMin", 2); -pref("extensions.keefox@chris.tomlinson.metricsUsageDisabled", false); pref("extensions.keefox@chris.tomlinson.maxMatchedLoginsInMainPanel", 5); pref("extensions.keefox@chris.tomlinson.maxAllLoginsInMainPanel", 0); pref("extensions.keefox@chris.tomlinson.tabResultsCacheEnabled", true); diff --git a/Firefox addon/KeeFox/modules/DataMigration.js b/Firefox addon/KeeFox/modules/DataMigration.js index ed11c98..c58d2d7 100644 --- a/Firefox addon/KeeFox/modules/DataMigration.js +++ b/Firefox addon/KeeFox/modules/DataMigration.js @@ -64,8 +64,8 @@ var DataMigration = { fullConfig.logMethodConsole = KFExtension.prefs.getValue("logMethodConsole", false); fullConfig.logMethodFile = KFExtension.prefs.getValue("logMethodFile", false); fullConfig.logSensitiveData = KFExtension.prefs.getValue("logSensitiveData", false); - fullConfig.metricsUsageDisabled = KFExtension.prefs.getValue("metricsUsageDisabled", false); - fullConfig.metricsUserId = KFExtension.prefs.getValue("metricsUserId", ""); + fullConfig.metricsUsageDisabled = false; + fullConfig.metricsUserId = ""; fullConfig.notifyWhenEntryUpdated = KFExtension.prefs.getValue("notifyWhenEntryUpdated", true); fullConfig.notifyWhenLateDiscovery = KFExtension.prefs.getValue("notifyWhenLateDiscovery", true); fullConfig.notifyWhenLoggedOut = KFExtension.prefs.getValue("notifyWhenLoggedOut", false); diff --git a/Firefox addon/KeeFox/modules/KF.js b/Firefox addon/KeeFox/modules/KF.js index 02b1973..d28b5a1 100644 --- a/Firefox addon/KeeFox/modules/KF.js +++ b/Firefox addon/KeeFox/modules/KF.js @@ -32,7 +32,6 @@ var EXPORTED_SYMBOLS = ["keefox_org"]; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://kfmod/KFLogger.js"); -Cu.import("resource://kfmod/metrics.js"); Cu.import("resource://kfmod/jsonrpcClient.js"); Cu.import("resource://kfmod/locales.js"); Cu.import("resource://kfmod/utils.js"); @@ -105,33 +104,6 @@ function KeeFox() this.locale = new Localisation(["chrome://keefox/locale/keefox.properties"]); - // Set up metrics recording but don't break the main addon if something unexpected happens - try - { - // Most of the metrics manager startup code is asynchronous so there is a - // race between the manager and the rest of the KeeFox startup code. I - // think this has been covered in the design of the manager (e.g. with - // temporary storage of metrics while the main storage subsystems - // initialise) but even if I've got that 100% correct, it is a shame to - // double-handle the activity that occurs before the manager is ready - // so it may be worth refactoring a few other parts of KeeFox to allow - // us to start the metrics manager initialisation sooner. - this.metricsManager = metricsManager; - let metricsUserId = this._keeFoxExtension.prefs.getValue("metricsUserId", ""); - if (!metricsUserId) - { - metricsUserId = this.utils.newGUID(); - this._keeFoxExtension.prefs.setValue("metricsUserId", metricsUserId); - } - this.metricsManager.init(this.locale.getCurrentLocale(), metricsUserId, this.utils.newGUID()); - } catch (e) { - this._KFLog.error("Could not load metrics manager. Creating null functions to minimise disruption."); - this.metricsManager = {}; - this.metricsManager.pushEvent = function () {}; - this.metricsManager.adjustAggregate = function () {}; - this.metricsManager.setApplicationMetadata = function () {}; - } - this.search = new Search(this, { version: 1, searchAllDatabases: this._keeFoxExtension.prefs.getValue("searchAllOpenDBs", true) @@ -507,8 +479,6 @@ KeeFox.prototype = { } this.KeePassDatabases = newDatabases; this.ActiveKeePassDatabaseIndex = newDatabaseActiveIndex; - if (newDatabases.length > 0) - this.metricsManager.adjustAggregate("avgOpenDatabases", newDatabases.length); this._refreshKPDBCallback(); }, @@ -1228,8 +1198,6 @@ KeeFox.prototype = { uninstallFeedback: function (disabling) { let [ connectState, setupState, setupActive, tutorialProgress ] = keefox_org.getAddonState(); - keefox_org.metricsManager.pushEvent("uninstall", disabling ? "disable" : "uninstall", - { "connectState": connectState, "setupState": setupState, "setupActive": setupActive, "tutorialProgress": tutorialProgress }, true); var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); var window = wm.getMostRecentWindow("navigator:browser") || @@ -1240,9 +1208,6 @@ KeeFox.prototype = { abortedUninstallFeedback: function () { let [ connectState, setupState, setupActive, tutorialProgress ] = keefox_org.getAddonState(); - - keefox_org.metricsManager.pushEvent("uninstall", "abort", { - "connectState": connectState, "setupState": setupState, "setupActive": setupActive, "tutorialProgress": tutorialProgress }, true); }, getAddonState: function () diff --git a/Firefox addon/KeeFox/modules/TutorialHelper.js b/Firefox addon/KeeFox/modules/TutorialHelper.js index 0da4c98..8c26f30 100644 --- a/Firefox addon/KeeFox/modules/TutorialHelper.js +++ b/Firefox addon/KeeFox/modules/TutorialHelper.js @@ -110,23 +110,13 @@ let TutorialHelper = function() this.sendSetupStateToTutorial = function (browser) { let [ connectState, setupState, setupActive, notUsed, dbState ] = browser.ownerGlobal.keefox_org.getAddonState(); - // We have probably already worked out our version string (but maybe not if the - // tutorial page is loaded during session restore) - if (browser.ownerGlobal.keefox_org.metricsManager.ii.addonVersion) { + Components.utils.import("resource://gre/modules/AddonManager.jsm"); + AddonManager.getAddonByID("keefox@chris.tomlinson", function(addon) { browser.messageManager.sendAsyncMessage("keefox:sendStatusToTutorialPage", { "connectState": connectState, "setupState": setupState, "setupActive": setupActive, - "version": browser.ownerGlobal.keefox_org.metricsManager.ii.addonVersion, + "version": addon.version, "dbState": dbState }); - } else - { - Components.utils.import("resource://gre/modules/AddonManager.jsm"); - AddonManager.getAddonByID("keefox@chris.tomlinson", function(addon) { - browser.messageManager.sendAsyncMessage("keefox:sendStatusToTutorialPage", { - "connectState": connectState, "setupState": setupState, "setupActive": setupActive, - "version": addon.version, - "dbState": dbState }); - }); - } + }); }; this.mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); diff --git a/Firefox addon/KeeFox/modules/commands.js b/Firefox addon/KeeFox/modules/commands.js index 945688f..5bede8f 100644 --- a/Firefox addon/KeeFox/modules/commands.js +++ b/Firefox addon/KeeFox/modules/commands.js @@ -405,7 +405,6 @@ function commandManager () { let win = utils.getWindow(); if (!win) return; - win.keefox_org.metricsManager.pushEvent ("feature", "detectForms"); var currentGBrowser = win.gBrowser; // Notify all parts of the UI that might need to clear their matched logins data win.keefox_win.mainUI.resetSearchInterface(); @@ -569,7 +568,6 @@ function commandManager () { if (!keefox_org.commandManager.conditions[commandName]()) continue; keefox_org._KFLog.debug("Executing command action: " + commandName); - keefox_org.metricsManager.adjustAggregate("keyboardShortcutsPressed", 1); //TODO:2: Pass event target information to action keefox_org.commandManager.actions[commandName](); break; @@ -690,7 +688,6 @@ function commandManager () { item.keeFoxValidContexts = this.commands[i].contextLocationFlags; item.addEventListener("command", function(event) { let kf = utils.getWindow().keefox_org; - kf.metricsManager.adjustAggregate("contextMenuItemsPressed", 1); kf.commandManager.actions[this.keeFoxCommandName](); }, false); } diff --git a/Firefox addon/KeeFox/modules/jsonrpcClient.js b/Firefox addon/KeeFox/modules/jsonrpcClient.js index c11cacb..5e9fbe5 100644 --- a/Firefox addon/KeeFox/modules/jsonrpcClient.js +++ b/Firefox addon/KeeFox/modules/jsonrpcClient.js @@ -179,9 +179,6 @@ jsonrpcClient.prototype.constructor = jsonrpcClient; netRuntimeVersion = "Mono " + resultWrapper.result.monoVersion; else netRuntimeVersion = ".NET " + resultWrapper.result.nETversion; - - window.keefox_org.metricsManager.setApplicationMetadata( - resultWrapper.result.keePassVersion, netRuntimeVersion); } diff --git a/Firefox addon/KeeFox/modules/metrics.js b/Firefox addon/KeeFox/modules/metrics.js deleted file mode 100644 index 604930b..0000000 --- a/Firefox addon/KeeFox/modules/metrics.js +++ /dev/null @@ -1,824 +0,0 @@ -/* - KeeFox - Allows Firefox to communicate with KeePass (via the KeePassRPC KeePass plugin) - Copyright 2008-2014 Chris Tomlinson - - The metrics module collects anonymous statistics about key metrics and - behaviours so we can improve KeeFox. - - https://addons.mozilla.org/en-US/firefox/addon/keefox/privacy/ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -"use strict"; - -let Cc = Components.classes; -let Ci = Components.interfaces; -let Cu = Components.utils; - -var EXPORTED_SYMBOLS = ["metricsManager"]; -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/ISO8601DateUtils.jsm"); -Cu.import("resource://kfmod/KFLogger.js"); -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/Timer.jsm"); -Cu.importGlobalProperties(["XMLHttpRequest"]); - -// A struct to represent information that won't change for a given session. -// In most cases, we'll only want to send this data once but there are a few exceptions. -function ImmutableInformation() -{ - this.userId; - this.sessionId; - this.OSType; - this.OSVersion; - this.browserType; - this.browserVersion; - this.addonVersion; - this.locale; - this.sessionStart; - this.screenWidth; - this.screenHeight; - this.keePassVersion; - this.netRuntimeVersion; -} - -function mm () { - - // where we'll POST the data to - this.url = "https://anonymousstats.keefox.org/in"; - - // Usual logging object - this._KFLog = KeeFoxLog; - - // Timer to process queued messages at regular intervals - this.metricsTimer = null; - - // Track metrics data submitted before the module has finished initialising - this.messagesQueue = []; - this.aggregatesQueue = []; - this.messagesReady = false; - this.aggregatesReady = false; - this.nextRequestTimeout = 30000; // 30 seconds - - this.init = function (locale, userId, sessionId) - { - this.ii = new ImmutableInformation(); - - this.ii.locale = locale; - this.ii.userId = userId; - this.ii.sessionId = sessionId; - this.ii.sessionStart = ISO8601DateUtils.create(new Date()); - - this.ii.browserType = Services.appinfo.name; - this.ii.browserVersion = Services.appinfo.version; - - // OS type - this.ii.OSType = Services.appinfo.OS; - - // OS version string - try { - this.ii.OSversion = Components.classes["@mozilla.org/network/protocol;1?name=http"] - .getService(Components.interfaces.nsIHttpProtocolHandler).oscpu; - } catch (ex) - { - this.ii.OSversion = "Unknown"; - } - - // We need a closure on this metrics module so we can manipulate it in - // the many callbacks required to keep things nice and asynchronous - var mm = this; - - // We can't start sending metrics data until Firefox has told us what - // we need to know (so far that's just the addon version) - // Other code may log events before we get to this callback so - // startSession will always make sure it is pushed to the front of the - // queue before converting transient storage to persistent storage. - // This might mean that the session start time is later than the first - // events recorded in the session but if that becomes a problem it can - // be resolved retrospectively during analysis becuase the session ID - // is included with every message - AddonManager.getAddonByID("keefox@chris.tomlinson", function(addon) { - mm.metricsStartup (addon, mm); - } - ); - }; - - this.metricsStartup = function (addon, mm) { - mm._KFLog.debug("Metrics startup for KeeFox version: " + addon.version); - - mm.ii.addonVersion = addon.version; - - // Make sure indexedDB is available somewhere consistent regardless - // of old Firefox differences. - // - // We can't assume that indexedDB and IDBKeyRange are accessed in the same - // way because there are definitely some non-release builds of Firefox - // where they differ but it does appear that they are consistently available - // if initWindowless() works. - if (typeof indexedDB !== "undefined") - { - mm.indexedDB = indexedDB; - } - if (!mm.indexedDB) { - try { - let idbManager = Cc["@mozilla.org/dom/indexeddb/manager;1"]. - getService(Ci.nsIIndexedDatabaseManager); - idbManager.initWindowless(mm); - } catch (e) - { - // May have just failed becuase the API changed again so that - // calls to initWindowless now need to be replaced by... - try - { - Cu.importGlobalProperties(["indexedDB"]); - mm.indexedDB = indexedDB; - } - catch (ie) - { - // Still broken, we'll have to accept that the whole metrics - // system is fragile until Firefox settles on a stable API for IndexedDB... - mm._KFLog.info("KeeFox metrics system disabled due to exception: " + e + " and 2nd exception: " + ie); - return; - } - } - } - - if (!mm.IDBKeyRange) { - mm.IDBKeyRange = IDBKeyRange; - } - if (!mm.IDBKeyRange) { - try - { - Cu.importGlobalProperties(["IDBKeyRange"]); - mm.IDBKeyRange = IDBKeyRange; - } - catch (e) - { - // Still broken, we'll have to accept that the whole metrics - // system is fragile until Firefox settles on a stable API for IndexedDB... - mm._KFLog.info("KeeFox metrics system disabled because IDBKeyRange is not available in this Firefox build. Exception: " + e); - return; - } - } - - // Open a uniquely named database - var request = mm.indexedDB.open("keefox@chris.tomlinson",4); - - // Not sure why this error could occur (no local disk space?) but - // being able to track the failure might help us fix it in a - // future KeeFox release - request.onerror = function(event) { - let errMsg = ""; - if (event.target.error.name) - errMsg += event.target.error.name + " - "; - if (event.target.error && event.target.error.message) - errMsg += event.target.error.message; - - mm._KFLog.error("Metrics system could not open/create the indexedDB. " + errMsg); - - if (event.target.error.name == "VersionError") - { - // try fixing things by deleting the stored metrics and starting again - var DBDeleteRequest = mm.indexedDB.deleteDatabase("keefox@chris.tomlinson"); - DBDeleteRequest.onerror = function(event) { - mm._KFLog.error("Metrics system could delete the indexedDB."); - }; - DBDeleteRequest.onsuccess = function(event) { - mm._KFLog.warn("Metrics system deleted the indexedDB."); - // Try again in a bit - setTimeout(mm.metricsStartup, 10000, addon, mm); - }; - } else - { - // Try again in a couple of minutes - setTimeout(mm.metricsStartup, 120000, addon, mm); - } - }; - - // This event handles the event whereby a new version of the database needs to be created - // Either one has not been created before, or a new version number has been submitted via the - // window.indexedDB.open line above - request.onupgradeneeded = function(event) { - mm._KFLog.debug("Metrics indexedDB version upgrade started"); - var db = event.target.result; - - db.onerror = function(event) { - let errMsg = ""; - if (event.target.error.name) - errMsg += event.target.error.name + " - "; - if (event.target.error && event.target.error.message) - errMsg += event.target.error.message; - mm._KFLog.error("Metrics error: " + errMsg); - }; - //db.deleteObjectStore("keefox@chris.tomlinson-metrics-data"); - - // Create an objectStore for this database - var objectStore = db.createObjectStore("keefox@chris.tomlinson-metrics-messages", { keyPath:"id" }); - var objectStore2 = db.createObjectStore("keefox@chris.tomlinson-metrics-data", { keyPath:"key" }); - - mm._KFLog.debug("Metrics indexedDB version upgrade finished"); - }; - request.onsuccess = function(event) { - if (!request.result) - return; - - mm.db = request.result; - mm.db.onerror = function(event) { - let errMsg = ""; - if (event.target.error.name) - errMsg += event.target.error.name + " - "; - if (event.target.error && event.target.error.message) - errMsg += event.target.error.message; - mm._KFLog.error("Metrics error: " + errMsg); - }; - - // Find the highest id number we used in the last session, if it's - // null, we'll just reset to 1 (this data is not sent to the metrics server) - let objectStore = mm.db.transaction("keefox@chris.tomlinson-metrics-messages") - .objectStore("keefox@chris.tomlinson-metrics-messages"); - objectStore.openCursor(null, "prev").onsuccess = function(event) { - var cursor = event.target.result; - if (cursor) { - mm.nextId = cursor.key + 1; - } else - { - mm.nextId = 1; - } - - // count how many entries we already have queued up. Should - // usually be 0 or a small number but when the profile has - // been unable to send data for many months or years, the - // number of queued events could start to eat into - // available disk space so we put a limit on the total - // number of entries. - let req = objectStore.count(); - req.onsuccess = function(evt) { - if (evt.target.result >= 100000) - { - // Too many stored entries: 100000 = 25MB @ 0.25KB per message - mm._KFLog.error("Too many metrics messages. No new messages will be recorded."); - - // overwrite last stored message to record this error state - mm.nextId--; - let msg = { - "type": "event", - "userId": mm.ii.userId, - "sessionId": mm.ii.sessionId, - "category": "error", - "name": "indexedDBFull", - "params": { "message": "Too many messages" }, - "ts": ISO8601DateUtils.create(new Date()) - }; - mm.set("message",JSON.stringify(msg)); - - // Keep trying to clear the message queue backlog - mm._KFLog.debug("Creating a metrics timer."); - mm.metricsTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - mm.metricsTimer.initWithCallback(mm.metricsTimerHandler, - 15000, - Components.interfaces.nsITimer.TYPE_ONE_SHOT); - - // Don't do the usual session init. Therefore any - // messages created during this session will be logged - // into the temporary arrays but never get pushed - // into the main message database. - return; - } - - // Get server versions (these are probably unknown to start with - // but following a successful KeePassRPC connection, they will - // be stored for use in the next session) - mm.getApplicationMetadata(function () { - - // push initial session start message - mm.startSession(function () { - mm._KFLog.debug("Started a metrics session."); - - // We know we've sent the startSession message now so - // we can push any events that were queued temporarilly - mm.messagesReady = true; - - // If any messages have been sent to us while initialising, process them now - for (let i=0; i < mm.messagesQueue.length; i++) - mm.set("message", mm.messagesQueue[i].message); - mm.messagesQueue = []; - - // Remove the old session data now it has been sent - mm.resetAggregates(function () { - mm.aggregatesReady = true; - - // If any aggregate values have been sent to us while initialising, evaluate them now - for (let i=0; i < mm.aggregatesQueue.length; i++) - mm.adjustAggregate(mm.aggregatesQueue[i].key, mm.aggregatesQueue[i].value); - mm.aggregatesQueue = []; - - // Start a regular check for queued items that need pushing to the metrics server - // For users that have disabled the user data component, this is technically - // un-necessary unless they re-enable the collection during this session but - // it's a very cheap operation so firing the timer for everyone makes things simpler - mm._KFLog.debug("Creating a metrics timer."); - mm.metricsTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - mm.metricsTimer.initWithCallback(mm.metricsTimerHandler, - 15000, - Components.interfaces.nsITimer.TYPE_ONE_SHOT); - }); - }); - }); - }; - }; - }; - }; - - this.startSession = function (callback) - { - var mm = this; - var cb = callback; - let oldMetrics = this.calculatePreviousSessionMetrics(function (event) { - mm.systemData = { - "type": "sessionStart", - "userId": mm.ii.userId, - "sessionId": mm.ii.sessionId, - "sessionStart": mm.ii.sessionStart, - "previousSessionMetrics": mm.previousSessionMetrics, - "browserType": mm.ii.browserType, - "browserVersion": mm.ii.browserVersion, - "OSType": mm.ii.OSType, - "OSversion": mm.ii.OSversion, - "locale": mm.ii.locale, - "addonVersion": mm.ii.addonVersion, - "netRuntimeVersion": mm.ii.netRuntimeVersion, - "keePassVersion": mm.ii.keePassVersion - }; - mm.set("message", JSON.stringify(mm.systemData), function () { cb(); }); - }); - }; - - this.pushEvent = function(category, name, params, direct) // string, string, object of keys/vals, bool - { - // direct events never contain usage data - if (!direct && Services.prefs.getBoolPref("extensions.keefox@chris.tomlinson.metricsUsageDisabled")) - return; - - let msg = { - "type": direct ? "direct" : "event", - "userId": this.ii.userId, - "sessionId": this.ii.sessionId, - "category": category, - "name": name, - "params": params, - "ts": ISO8601DateUtils.create(new Date()) - }; - // Repeat basic system data for direct feedback to aid analysis - if (direct) { - msg.systemData = JSON.parse(JSON.stringify(this.systemData)); //TODO:2: less hacky clone. https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/The_structured_clone_algorithm ? - delete msg.systemData.previousSessionMetrics; - delete msg.systemData.type; - delete msg.systemData.userId; - delete msg.systemData.sessionId; - } - - let jMsg = JSON.stringify(msg); - if (direct) - this.deliverMessageDirect(jMsg); - else if (this.messagesReady) - this.set("message", jMsg); - else - this.messagesQueue.push( { "message": jMsg } ); - }; - - this.calculatePreviousSessionMetrics = function (callback) - { - if (Services.prefs.getBoolPref("extensions.keefox@chris.tomlinson.metricsUsageDisabled")) - { - this.previousSessionMetrics = null; - callback(); - return; - } - this.previousSessionMetrics = {}; - var mm = this; - var cb = callback; - this.get("databaseLoginCount", function (event) { - if (event.target.result) - mm.previousSessionMetrics.databaseLoginCount = event.target.result.value; - mm.get("contextMenuItemsPressed", function (event) { - if (event.target.result) - mm.previousSessionMetrics.contextMenuItemsPressed = event.target.result.value; - mm.get("keyboardShortcutsPressed", function (event) { - if (event.target.result) - mm.previousSessionMetrics.keyboardShortcutsPressed = event.target.result.value; - mm.get("avgOpenDatabases", function (event) { - if (event.target.result) - mm.previousSessionMetrics.avgOpenDatabases = event.target.result.value; // when any are open (so >= 1) - mm.get("copyUsername", function (event) { - if (event.target.result) - mm.previousSessionMetrics.copyUsername = event.target.result.value; - mm.get("copyPassword", function (event) { - if (event.target.result) - mm.previousSessionMetrics.copyPassword = event.target.result.value; - mm.get("copyOther", function (event) { - if (event.target.result) - mm.previousSessionMetrics.copyOther = event.target.result.value; - mm.get("searchResultSelectedAll", function (event) { - if (event.target.result) - mm.previousSessionMetrics.searchResultSelectedAll = event.target.result.value; - mm.get("searchResultSelectedCurrent", function (event) { - if (event.target.result) - mm.previousSessionMetrics.searchResultSelectedCurrent = event.target.result.value; - mm.get("searchResultContextAll", function (event) { - if (event.target.result) - mm.previousSessionMetrics.searchResultContextAll = event.target.result.value; - mm.get("searchResultContextCurrent", function (event) { - if (event.target.result) - mm.previousSessionMetrics.searchResultContextCurrent = event.target.result.value; - mm.get("loginContextButton", function (event) { - if (event.target.result) - mm.previousSessionMetrics.loginContextButton = event.target.result.value; - mm.get("pseudoFormCreated", function (event) { - if (event.target.result) - mm.previousSessionMetrics.pseudoFormCreated = event.target.result.value; - //TODO:2: Try to convert to Promises so we can avoid infinite callback indentation - mm._KFLog.debug("calculatePreviousSessionMetrics finished"); - if (cb) cb(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - // future: timing e.g. time logged in to database, time taken to decrypt messages, time from setup screen displayed to successful login , etc. - some of these might be more suited to specific event params - } - - this.getApplicationMetadata = function (callback) - { - this.ii.keePassVersion = "unknown"; - this.ii.netRuntimeVersion = "unknown"; - - var mm = this; - var cb = callback; - this.get("keePassVersion", function (event) { - if (event.target.result) - mm.ii.keePassVersion = event.target.result.value; - mm.get("netRuntimeVersion", function (event) { - if (event.target.result) - mm.ii.netRuntimeVersion = event.target.result.value; - if (cb) cb(); - }); - }); - }; - - this.setApplicationMetadata = function (keePassVersion, netRuntimeVersion) - { - this.set("keePassVersion", keePassVersion); - this.set("netRuntimeVersion", netRuntimeVersion); - }; - - this.set = function (key, value, callback) - { - if (!this.db) return; - - let cb = callback; - let mm = this; - - if (key === "message") - { - var newMessage = { "id": mm.nextId++, "msg": value }; - var request = mm.db.transaction(["keefox@chris.tomlinson-metrics-messages"], "readwrite") - .objectStore("keefox@chris.tomlinson-metrics-messages").put(newMessage); - request.onsuccess = function(e) { - if (cb) cb(); - } - } - else - { - var newItem = { "key": key, "value": value }; - var request = mm.db.transaction(["keefox@chris.tomlinson-metrics-data"], "readwrite") - .objectStore("keefox@chris.tomlinson-metrics-data").put(newItem); - request.onsuccess = function(e) { - if (cb) cb(); - } - } - }; - - // messages are always retrieved in batches from a cursor so this - // only deals with specific data metrics - this.get = function (key, callback) - { - return this.db.transaction(["keefox@chris.tomlinson-metrics-data"], "readonly") - .objectStore("keefox@chris.tomlinson-metrics-data").get(key).onsuccess = callback; - }; - - // Grab the messages waiting to be sent to the remote server - this.processQueue = function () - { - if (!this.db) return; - - let completeMessage = ""; - var objectStore = this.db.transaction("keefox@chris.tomlinson-metrics-messages") - .objectStore("keefox@chris.tomlinson-metrics-messages"); - let mm = this; - - let cursorReq = objectStore.openCursor(); - cursorReq.onsuccess = function(event) { - var cursor = event.target.result; - if (cursor) { - // Don't append exceptionally large messages to the current message - // string - we'll leave it for next time and send it on its own - if (completeMessage !== "" && completeMessage.length + cursor.value.msg.length > 250000) - { - try { - mm.deliverMessage(completeMessage); - } catch (e) { - mm._KFLog.warn("Metrics processQueue failed to deliverMessage (large). We'll try again later."); - } - // Don't respawn here since deliverMessage should do that. - // Stop iterating this cursor - return; - } - - mm.lastSentAttemptId = cursor.value.id; - completeMessage += cursor.value.msg; - cursor.continue(); - } - else { - // We've reached the end of the cursor, whether we - // found any results is another matter... - if (completeMessage.length > 0) - mm.deliverMessage(completeMessage); - else - mm.metricsTimerRespawn(); - } - }; - - cursorReq.onerror = function(event) { - // Try again later if something forced us to abort - mm._KFLog.warn("Metrics processQueue failed to iterate cursor (" + cursorReq.error.name + ")."); - if (cursorReq.error.name == "AbortError") { - mm.metricsTimerRespawn(60); - } - }; - - }; - - // Start the timer ready for the next queue processing operation - this.metricsTimerRespawn = function (retry) - { - try { - let DEFAULT_DELAY = 15; - let secondsUntilNextProcess = DEFAULT_DELAY; - - // retry should have been set on failure but may also be set by server to manage load - if (retry) - { //TODO:1.6: Don't just listen to the server - do something more useful - secondsUntilNextProcess = retry; - if (secondsUntilNextProcess < DEFAULT_DELAY) - secondsUntilNextProcess = DEFAULT_DELAY; - } - - var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] - .getService(Ci.nsIWindowMediator); - var window = wm.getMostRecentWindow("navigator:browser") || - wm.getMostRecentWindow("mail:3pane"); - var mm = window.keefox_org.metricsManager; - - mm.metricsTimer.initWithCallback(mm.metricsTimerHandler, - secondsUntilNextProcess * 1000, - Components.interfaces.nsITimer.TYPE_ONE_SHOT); - } catch (e) - { - //TODO:1.6: Review need for this try/catch - // Do nothing (can't be sure if we can log safely but this is just a test anyway for the moment... - } - }; - - // Just process the message queue when the timer fires - this.metricsTimerHandler = { - notify: function(timer) { - var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] - .getService(Ci.nsIWindowMediator); - var window = wm.getMostRecentWindow("navigator:browser") || - wm.getMostRecentWindow("mail:3pane"); - var mm = window.keefox_org.metricsManager; - mm.processQueue(); - } - }; - - this.createXMLHttpRequest = function () { - let request; - try { - // Enable an anonymous request (no cookies). The only feasible risk from not - // doing this is if someone takes control of the KeeFox metrics server and - // starts parsing the Google Analytics tracking cookies that are used - // elsewhere on the keefox.org domain. They'd also have to intercept the - // analytics cookies on the way to the KeeFox website to have any hope of - // linking activity on the keefox site to the metrics data. Google is obviously - // best placed to initiate this attack but it's still going to be very - // difficult for them and will provide no tangible benefit to them (or - // any other attacker). Still, since we can, let's protect against the possibility. - request = new XMLHttpRequest({ mozAnon: true }); - } catch (e) { - // Protecting against future removal of mozAnon parameter - request = new XMLHttpRequest(); - } - return request; - }; - - // Send a message containing one or more metrics messages - this.deliverMessage = function (msg) - { - var mm = this; - - // No need to debug metric data in normal circumstances, only dev work - //this._KFLog.debug("METRIC to be sent: " + msg); - this._KFLog.debug("metrics being sent"); - - try{ - var request = this.createXMLHttpRequest(); - request.open("POST", this.url, true); - request.addEventListener("load", function(event) { - // Note our success position in the queue so we can remove the old ones - mm.lastSentId = mm.lastSentAttemptId; - - // Remove the old messages - var objectStore = mm.db.transaction("keefox@chris.tomlinson-metrics-messages","readwrite") - .objectStore("keefox@chris.tomlinson-metrics-messages"); - - let cursorReq = objectStore.openCursor(mm.IDBKeyRange.upperBound(mm.lastSentId)); - cursorReq.onsuccess = function(event) { - var cursor = event.target.result; - if (cursor) { - cursor.delete(); - // This seemed to work too but maybe susceptible to concurrency bugs? objectStore.delete(cursor.primaryKey); - cursor.continue(); - } else - { - mm.metricsTimerRespawn(15); - } - }; - cursorReq.onerror = function(event) { - // Try again later if something forced us to abort - mm._KFLog.warn("Metrics deliverMessage failed to iterate cursor (" + cursorReq.error.name + ")."); - if (cursorReq.error.name == "AbortError") { - mm.metricsTimerRespawn(60); - } - }; - - }); - request.addEventListener("error", function(event) { - mm._KFLog.debug("Metrics could not be sent."); - mm.metricsTimerRespawn(); - }); - request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - - // We'll set a timeout to prevent the metrics collection - // hanging forever following a single dodgy connection. - - request.timeout = mm.nextRequestTimeout; - request.ontimeout = function(event) { - if (mm.nextRequestTimeout >= 1920000) { // 32 minutes - mm._KFLog.info("Metrics timeout. Can't increase any higher. There is probably an internet connection fault."); - } else { - mm.nextRequestTimeout = mm.nextRequestTimeout * 2; - mm._KFLog.debug("Metrics timeout. Increasing to " + mm.nextRequestTimeout + "ms"); - } - mm.metricsTimerRespawn(); - }; - request.send(msg); - } catch (ex) - { - mm._KFLog.error("Metrics error. Could not send because: " + ex); - mm.metricsTimerRespawn(60); - } - }; - - // Send a message containing one or more metrics messages directly to the metrics - // server, out of sync with the usual regular message interval. - this.deliverMessageDirect = function (msg) { - // No need to debug metric data in normal circumstances, only dev work - //this._KFLog.debug("METRIC to be sent directly: " + msg); - this._KFLog.debug("metrics being sent directly"); - - try { - var request = this.createXMLHttpRequest(); - request.open("POST", this.url, true); - request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - request.timeout = this.nextRequestTimeout; - request.send(msg); - } catch (ex) { - this._KFLog.error("Metrics error. Could not send directly because: " + ex); - } - }; - - // all aggregate data will be reset at the start of each session. Aggregation - // across longer periods of time can still be done in some post-processing - // of the received data but this short aggregation period will allow us to - // spot changes quickly. - this.resetAggregates = function (callback) - { - // We do this even if aggregate data collection has been disabled by - // the user because they might re-enable it during this session - let cb = callback; - let mm = this; - this._KFLog.debug("resetAggregates started"); - this.set("databaseLoginCount",{ value: 0.0 }, function () { - mm.set("contextMenuItemsPressed",{ value: 0.0 }, function () { - mm.set("keyboardShortcutsPressed",{ value: 0.0 }, function () { - mm.set("avgOpenDatabases",{ avg: 0.0, count: 0 }, function () { - mm.set("copyUsername",{ value: 0.0 }, function () { - mm.set("copyPassword",{ value: 0.0 }, function () { - mm.set("copyOther",{ value: 0.0 }, function () { - mm.set("searchResultSelectedAll", { value: 0.0 }, function () { - mm.set("searchResultSelectedCurrent", { value: 0.0 }, function () { - mm.set("searchResultContextAll", { value: 0.0 }, function () { - mm.set("searchResultContextCurrent", { value: 0.0 }, function () { - mm.set("loginContextButton", { value: 0.0 }, function () { - mm.set("pseudoFormCreated", { value: 0.0 }, function () { - mm.aggregatesReady = true; - mm._KFLog.debug("resetAggregates finished"); - if (cb) cb(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }; - - this.adjustAggregate = function (key, value) - { - if (Services.prefs.getBoolPref("extensions.keefox@chris.tomlinson.metricsUsageDisabled")) - return; - - var mm = this; - if (this.aggregatesReady) - { - // We might log two new aggregate data points in a short period of time - // and the async behaviour of indexedDB means that some of these data - // points may be missed. - // This might be particularly likely during startup since we have to just - // fire all the queued events as quickly as possible to avoid race - // conditions with newly created data points. - // It should be possible to work around this with the co-operation of all - // callers but I think it will be too complicated to be worthwhile now. - this.get(key, function (event) - { - let result = event.target.result; - let agg = result.value; - if (agg.value != undefined) - { - if (agg.value > 0) - agg.value = agg.value + value; - else - agg.value = value; - } else if (agg.avg != undefined) - { - let newCount = agg.count + 1.0; - let total = agg.avg * agg.count + value; - agg.avg = total/newCount; - agg.count = newCount; - } - mm.set(key, agg); - } - ); - } else - { - this.aggregatesQueue.push( { "key": key, "value": value } ); - } - }; - -} - -var metricsManager = new mm; - -let globalMM = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); -globalMM.addMessageListener("keefox:metrics-pushEvent", function (message) { - metricsManager.pushEvent(message.data.category, message.data.name, message.data.params); }); -globalMM.addMessageListener("keefox:metrics-adjustAggregate", function (message) { - metricsManager.adjustAggregate(message.data.key, message.data.value); }); \ No newline at end of file