Source code
Revision control
Copy as Markdown
Other Tools
/* 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
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ExperimentAPI: "resource://nimbus/ExperimentAPI.sys.mjs",
});
const SHIELD_LEARN_MORE_URL_PREF = "app.normandy.shieldLearnMoreUrl";
XPCOMUtils.defineLazyPreferenceGetter(
lazy,
"gOptOutStudiesEnabled",
"app.shield.optoutstudies.enabled"
);
/**
* The module exported by this file.
*/
export let AboutStudies = {};
/**
* The weak set that keeps track of which browsing contexts
* have an about:studies page.
*/
let BrowsingContexts = new WeakSet();
/**
* about:studies page for displaying in-progress and past Shield studies.
*
* @type {AboutPage}
* @implements {nsIMessageListener}
*/
ChromeUtils.defineLazyGetter(
AboutStudies,
"aboutStudies",
() =>
new (class {
getMessagingSystemList() {
const debugEnabled = Services.prefs.getBoolPref("nimbus.debug");
// Do not include Firefox Labs. Those are shown on
// about:preferences#experimental.
//
// Only show Rollouts if nimbus.debug is enabled.
return lazy.ExperimentAPI.manager.store
.getAll()
.filter(e => !e.isFirefoxLabsOptIn && (debugEnabled || !e.isRollout));
}
async optInToExperiment(data) {
try {
await lazy.ExperimentAPI.optInToExperiment(data);
return {
error: false,
message: "Opt-in was successful.",
};
} catch (error) {
return {
error: true,
message: error.message,
};
}
}
/**
* Add a browsing context to the weak set;
* this weak set keeps track of all contexts
* that are housing an about:studies page.
*/
addToWeakSet(browsingContext) {
BrowsingContexts.add(browsingContext);
}
/**
* Remove a browsing context to the weak set;
* this weak set keeps track of all contexts
* that are housing an about:studies page.
*/
removeFromWeakSet(browsingContext) {
BrowsingContexts.delete(browsingContext);
}
/**
* Sends a message to every about:studies page,
* by iterating over the BrowsingContexts weakset.
*
* @param {string} message The message string to send to.
* @param {object} data The data object to send.
*/
_sendToAll(message, data) {
ChromeUtils.nondeterministicGetWeakSetKeys(BrowsingContexts).forEach(
browser =>
browser.currentWindowGlobal
.getActor("AboutStudies")
.sendAsyncMessage(message, data)
);
}
/**
* Get if studies are enabled. This has to be in the parent process,
* since RecipeRunner is stateful, and can't be interacted with from
* content processes safely.
*/
async getStudiesEnabled() {
await lazy.RecipeRunner.initializedPromise.promise;
return lazy.RecipeRunner.enabled && lazy.gOptOutStudiesEnabled;
}
async removeMessagingSystemExperiment(slug) {
lazy.ExperimentAPI.manager.unenroll(
slug,
lazy.UnenrollmentCause.fromReason(
lazy.NimbusTelemetry.UnenrollReason.INDIVIDUAL_OPT_OUT
)
);
this._sendToAll(
"Shield:UpdateMessagingSystemExperimentList",
this.getMessagingSystemList()
);
}
openDataPreferences() {
const browserWindow =
Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.openPreferences("privacy-reports");
}
getShieldLearnMoreHref() {
return Services.urlFormatter.formatURLPref(SHIELD_LEARN_MORE_URL_PREF);
}
})()
);