mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
6407007ebd
Differential Revision: https://phabricator.services.mozilla.com/D26945 --HG-- extra : moz-landing-system : lando
148 lines
4.7 KiB
JavaScript
148 lines
4.7 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
var EXPORTED_SYMBOLS = [
|
|
"PermissionUITelemetry",
|
|
];
|
|
|
|
ChromeUtils.defineModuleGetter(this, "Services",
|
|
"resource://gre/modules/Services.jsm");
|
|
ChromeUtils.defineModuleGetter(this, "CryptoUtils",
|
|
"resource://services-crypto/utils.js");
|
|
|
|
const TELEMETRY_STAT_REMOVAL_LEAVE_PAGE = 6;
|
|
|
|
var PermissionUITelemetry = {
|
|
// Returns a hash of the host name in combination with a unique local user id.
|
|
// This allows us to track duplicate prompts on sites while not revealing the user's
|
|
// browsing history.
|
|
_uniqueHostHash(host) {
|
|
// Gets a unique user ID as salt, that needs to stay local to this profile and not be
|
|
// sent to any server!
|
|
let salt = Services.prefs.getStringPref("permissions.eventTelemetry.salt", null);
|
|
if (!salt) {
|
|
salt = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)
|
|
.generateUUID().toString();
|
|
Services.prefs.setStringPref("permissions.eventTelemetry.salt", salt);
|
|
}
|
|
|
|
let domain;
|
|
try {
|
|
domain = Services.eTLD.getBaseDomainFromHost(host);
|
|
} catch (e) {
|
|
domain = host;
|
|
}
|
|
|
|
return CryptoUtils.sha256(domain + salt);
|
|
},
|
|
|
|
_previousVisitCount(host) {
|
|
let historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
|
|
.getService(Ci.nsINavHistoryService);
|
|
|
|
let options = historyService.getNewQueryOptions();
|
|
options.resultType = options.RESULTS_AS_VISIT;
|
|
|
|
// Search for visits to this host before today
|
|
let query = historyService.getNewQuery();
|
|
query.endTimeReference = query.TIME_RELATIVE_TODAY;
|
|
query.endTime = 0;
|
|
query.domain = host;
|
|
|
|
let result = historyService.executeQuery(query, options);
|
|
result.root.containerOpen = true;
|
|
let cc = result.root.childCount;
|
|
result.root.containerOpen = false;
|
|
return cc;
|
|
},
|
|
|
|
_collectExtraKeys(prompt) {
|
|
let lastInteraction = 0;
|
|
// "storageAccessAPI" is the name of the permission that tells us whether the
|
|
// user has interacted with a particular site in the first-party context before.
|
|
let interactionPermission = Services.perms.getPermissionObject(
|
|
prompt.principal, "storageAccessAPI", false);
|
|
if (interactionPermission) {
|
|
lastInteraction = interactionPermission.modificationTime;
|
|
}
|
|
|
|
let allPermsDenied = 0;
|
|
let allPermsGranted = 0;
|
|
let thisPermDenied = 0;
|
|
let thisPermGranted = 0;
|
|
|
|
let commonPermissions = ["geo", "desktop-notification", "camera", "microphone", "screen"];
|
|
for (let perm of Services.perms.enumerator) {
|
|
if (!commonPermissions.includes(perm.type)) {
|
|
continue;
|
|
}
|
|
|
|
if (perm.capability == Services.perms.ALLOW_ACTION) {
|
|
allPermsGranted++;
|
|
if (perm.type == prompt.permissionKey) {
|
|
thisPermGranted++;
|
|
}
|
|
}
|
|
|
|
if (perm.capability == Services.perms.DENY_ACTION) {
|
|
allPermsDenied++;
|
|
if (perm.type == prompt.permissionKey) {
|
|
thisPermDenied++;
|
|
}
|
|
}
|
|
}
|
|
|
|
let promptHost = prompt.principal.URI.host;
|
|
|
|
return {
|
|
previousVisits: this._previousVisitCount(promptHost).toString(),
|
|
timeOnPage: (Date.now() - prompt.documentDOMContentLoadedTimestamp).toString(),
|
|
hasUserInput: prompt.isHandlingUserInput.toString(),
|
|
docHasUserInput: prompt.userHadInteractedWithDocument.toString(),
|
|
lastInteraction: lastInteraction.toString(),
|
|
allPermsDenied: allPermsDenied.toString(),
|
|
allPermsGranted: allPermsGranted.toString(),
|
|
thisPermDenied: thisPermDenied.toString(),
|
|
thisPermGranted: thisPermGranted.toString(),
|
|
};
|
|
},
|
|
|
|
onShow(prompt) {
|
|
let object = prompt.permissionTelemetryKey;
|
|
if (!object) {
|
|
return;
|
|
}
|
|
|
|
let extraKeys = this._collectExtraKeys(prompt);
|
|
let hostHash = this._uniqueHostHash(prompt.principal.URI.host);
|
|
Services.telemetry.recordEvent("security.ui.permissionprompt",
|
|
"show", object, hostHash, extraKeys);
|
|
},
|
|
|
|
onRemoved(prompt, buttonAction, telemetryReason) {
|
|
let object = prompt.permissionTelemetryKey;
|
|
if (!object) {
|
|
return;
|
|
}
|
|
|
|
let method = "other";
|
|
if (buttonAction == "accept") {
|
|
method = "accept";
|
|
} else if (buttonAction == "deny") {
|
|
method = "deny";
|
|
} else if (buttonAction == "never") {
|
|
method = "never";
|
|
} else if (telemetryReason == TELEMETRY_STAT_REMOVAL_LEAVE_PAGE) {
|
|
method = "leave";
|
|
}
|
|
|
|
let extraKeys = this._collectExtraKeys(prompt);
|
|
let hostHash = this._uniqueHostHash(prompt.principal.URI.host);
|
|
Services.telemetry.recordEvent("security.ui.permissionprompt",
|
|
method, object, hostHash, extraKeys);
|
|
},
|
|
};
|