Bug 1490284 - Make Mozilla.ContentTelemetry.initPromise reject. r=chutten

This patch enables Hybrid Content Telemetry's |initPromise| to reject
if it is disabled or if the host requesting the API doesn't have
enough privileges. This also updates the documentation to mention
the change in behaviour.

Differential Revision: https://phabricator.services.mozilla.com/D5849

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alessio Placitelli 2018-09-14 20:36:44 +00:00
parent 750989d3fb
commit 29a1323c2d
4 changed files with 65 additions and 9 deletions

View File

@ -263,7 +263,7 @@ Example:
Mozilla.ContentTelemetry.initPromise();
This function returns a Promise that gets resolved as soon as Hybrid Content Telemetry is correctly initialized and the value from ``canUpload`` can be reliably read.
This function returns a Promise that gets resolved as soon as Hybrid Content Telemetry is correctly initialized and the value from ``canUpload`` can be reliably read. The promise will reject if Hybrid Content Telemetry is disabled or the host doesn't have enough privileges to use the API.
``Mozilla.ContentTelemetry.registerEvents()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -50,7 +50,7 @@ if (typeof Mozilla == "undefined") {
*/
function _registerInternalPolicyHandler() {
// Create a promise to wait on for HCT to be completely initialized.
_initPromise = new Promise(function(resolveInit) {
_initPromise = new Promise(function(resolveInit, rejectInit) {
// Register the handler that will update the policy boolean.
function policyChangeHandler(updatedPref) {
if (!("detail" in updatedPref) ||
@ -64,6 +64,9 @@ if (typeof Mozilla == "undefined") {
resolveInit();
}
document.addEventListener("mozTelemetryPolicyChange", policyChangeHandler);
document.addEventListener("mozTelemetryUntrustedOrigin",
() => rejectInit(new Error("Origin not trusted or HCT disabled.")),
{once: true});
});
// Make sure the chrome is initialized.

View File

@ -93,13 +93,14 @@ var HybridContentTelemetryListener = {
* {name: "apiEndpoint", data: { ... endpoint specific data ... }}
*/
handleEvent(event) {
if (!this._hybridContentEnabled) {
this._log.trace("handleEvent - hybrid content telemetry is disabled.");
return;
}
if (!this.isTrustedOrigin(event)) {
this._log.warn("handleEvent - accessing telemetry from an untrusted origin.");
const originNotTrusted = !this.isTrustedOrigin(event);
if (!this._hybridContentEnabled || originNotTrusted) {
this._log.warn(`handleEvent - hct disabled ${!this._hybridContentEnabled}, `
+ `untrusted origin ${originNotTrusted}.`);
let errorEvent = Cu.cloneInto({bubbles: true, detail: {}}, content);
content.document.dispatchEvent(
new content.document.defaultView.CustomEvent("mozTelemetryUntrustedOrigin", errorEvent)
);
return;
}

View File

@ -381,3 +381,55 @@ add_task(async function test_hct_for_discopane() {
ok(permission == Services.perms.ALLOW_ACTION, "Disco Pane needs Hybrid Content Permission for Telemetry data upload");
});
add_task(async function test_init_rejects() {
await SpecialPowers.pushPrefEnv({set: [[TelemetryUtils.Preferences.FhrUploadEnabled, true]]});
// Give the test host no privilege: init() will throw.
const testHostNoPrivilege = "https://example.org";
let url = getRootDirectory(gTestPath) + "hybrid_content.html";
url = url.replace("chrome://mochitests/content", testHostNoPrivilege);
let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
// Check that CanUpload reports false if we threw. We don't block on spawning
// the content task, as we want to spawn another tab that loads an URI with HCT
// privileges in order to make sure that init works ok there. We want both pages
// to load in parallel.
let page1Promise = ContentTask.spawn(newTab.linkedBrowser, {}, async function() {
let contentWin = Cu.waiveXrays(content);
await Assert.rejects(contentWin.Mozilla.ContentTelemetry.initPromise(),
/Origin not trusted/,
"The init promise must reject if the page has no HCT permission.");
// We don't need to pass any parameter, we can safely call Mozilla.ContentTelemetry.
let canUpload = contentWin.Mozilla.ContentTelemetry.canUpload();
ok(!canUpload, "CanUpload must report 'false' if init failed.");
});
// Give the test host HCT privileges and test that init doesn't throw.
const testHostPrivileges = "https://example.com";
let testUrlPrivileges = Services.io.newURI(testHostPrivileges);
Services.perms.add(testUrlPrivileges, HC_PERMISSION, Services.perms.ALLOW_ACTION);
let urlWithPrivs = getRootDirectory(gTestPath) + "hybrid_content.html";
urlWithPrivs = urlWithPrivs.replace("chrome://mochitests/content", testHostPrivileges);
let otherTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, urlWithPrivs);
// Check that CanUpload reports the correct value.
let page2Promise = ContentTask.spawn(otherTab.linkedBrowser, {}, async function() {
let contentWin = Cu.waiveXrays(content);
await contentWin.Mozilla.ContentTelemetry.initPromise();
// We don't need to pass any parameter, we can safely call Mozilla.ContentTelemetry.
let canUpload = contentWin.Mozilla.ContentTelemetry.canUpload();
ok(canUpload, "CanUpload must report the expected value if init succeeded.");
});
await Promise.all([page1Promise, page2Promise]);
// Cleanup permissions and remove the tab.
BrowserTestUtils.removeTab(newTab);
BrowserTestUtils.removeTab(otherTab);
Services.perms.remove(testUrlPrivileges, HC_PERMISSION);
});