diff options
Diffstat (limited to 'toolkit/components/normandy/content/ShieldFrameChild.sys.mjs')
-rw-r--r-- | toolkit/components/normandy/content/ShieldFrameChild.sys.mjs | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/toolkit/components/normandy/content/ShieldFrameChild.sys.mjs b/toolkit/components/normandy/content/ShieldFrameChild.sys.mjs new file mode 100644 index 0000000000..8ca4110f6d --- /dev/null +++ b/toolkit/components/normandy/content/ShieldFrameChild.sys.mjs @@ -0,0 +1,172 @@ +/* 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/. */ + +/** + * Listen for DOM events bubbling up from the about:studies page, and perform + * privileged actions in response to them. If we need to do anything that the + * content process can't handle (such as reading IndexedDB), we send a message + * to the parent process and handle it there. + */ + +import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs"; + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + AboutPages: "resource://normandy-content/AboutPages.sys.mjs", +}); + +XPCOMUtils.defineLazyGetter(lazy, "gBrandBundle", function () { + return Services.strings.createBundle( + "chrome://branding/locale/brand.properties" + ); +}); + +XPCOMUtils.defineLazyGetter(lazy, "gStringBundle", function () { + return Services.strings.createBundle( + "chrome://global/locale/aboutStudies.properties" + ); +}); + +const NIMBUS_DEBUG_PREF = "nimbus.debug"; + +/** + * Listen for DOM events bubbling up from the about:studies page, and perform + * privileged actions in response to them. If we need to do anything that the + * content process can't handle (such as reading IndexedDB), we send a message + * to the parent process and handle it there. + */ +export class ShieldFrameChild extends JSWindowActorChild { + async handleEvent(event) { + // On page show or page hide, + // add this child to the WeakSet in AboutStudies. + switch (event.type) { + case "pageshow": + this.sendAsyncMessage("Shield:AddToWeakSet"); + return; + + case "pagehide": + this.sendAsyncMessage("Shield:RemoveFromWeakSet"); + return; + } + switch (event.detail.action) { + // Actions that require the parent process + case "GetRemoteValue:AddonStudyList": + let addonStudies = await this.sendQuery("Shield:GetAddonStudyList"); + this.triggerPageCallback( + "ReceiveRemoteValue:AddonStudyList", + addonStudies + ); + break; + case "GetRemoteValue:PreferenceStudyList": + let prefStudies = await this.sendQuery("Shield:GetPreferenceStudyList"); + this.triggerPageCallback( + "ReceiveRemoteValue:PreferenceStudyList", + prefStudies + ); + break; + case "GetRemoteValue:MessagingSystemList": + let experiments = await this.sendQuery("Shield:GetMessagingSystemList"); + this.triggerPageCallback( + "ReceiveRemoteValue:MessagingSystemList", + experiments + ); + break; + case "RemoveAddonStudy": + this.sendAsyncMessage("Shield:RemoveAddonStudy", event.detail.data); + break; + case "RemovePreferenceStudy": + this.sendAsyncMessage( + "Shield:RemovePreferenceStudy", + event.detail.data + ); + break; + case "RemoveMessagingSystemExperiment": + this.sendAsyncMessage( + "Shield:RemoveMessagingSystemExperiment", + event.detail.data + ); + break; + case "GetRemoteValue:StudiesEnabled": + let studiesEnabled = await this.sendQuery("Shield:GetStudiesEnabled"); + this.triggerPageCallback( + "ReceiveRemoteValue:StudiesEnabled", + studiesEnabled + ); + break; + case "GetRemoteValue:DebugModeOn": + this.triggerPageCallback( + "ReceiveRemoteValue:DebugModeOn", + Services.prefs.getBoolPref(NIMBUS_DEBUG_PREF) + ); + break; + case "NavigateToDataPreferences": + this.sendAsyncMessage("Shield:OpenDataPreferences"); + break; + // Actions that can be performed in the content process + case "GetRemoteValue:ShieldLearnMoreHref": + this.triggerPageCallback( + "ReceiveRemoteValue:ShieldLearnMoreHref", + lazy.AboutPages.aboutStudies.getShieldLearnMoreHref() + ); + break; + case "GetRemoteValue:ShieldTranslations": + const strings = {}; + for (let str of lazy.gStringBundle.getSimpleEnumeration()) { + strings[str.key] = str.value; + } + const brandName = lazy.gBrandBundle.GetStringFromName("brandShortName"); + strings.enabledList = lazy.gStringBundle.formatStringFromName( + "enabledList", + [brandName] + ); + + this.triggerPageCallback( + "ReceiveRemoteValue:ShieldTranslations", + strings + ); + break; + case "ExperimentOptIn": + const message = await this.sendQuery( + "Shield:ExperimentOptIn", + event.detail.data + ); + this.triggerPageCallback("ReceiveRemoteValue:OptInMessage", message); + break; + } + } + + receiveMessage(msg) { + switch (msg.name) { + case "Shield:UpdateAddonStudyList": + this.triggerPageCallback("ReceiveRemoteValue:AddonStudyList", msg.data); + break; + case "Shield:UpdatePreferenceStudyList": + this.triggerPageCallback( + "ReceiveRemoteValue:PreferenceStudyList", + msg.data + ); + break; + case "Shield:UpdateMessagingSystemExperimentList": + this.triggerPageCallback( + "ReceiveRemoteValue:MessagingSystemList", + msg.data + ); + break; + } + } + /** + * Trigger an event to communicate with the unprivileged about:studies page. + * @param {String} type The type of event to trigger. + * @param {Object} detail The data to pass along to the event. + */ + triggerPageCallback(type, detail) { + // Clone details and use the event class from the unprivileged context. + const event = new this.document.defaultView.CustomEvent(type, { + bubbles: true, + detail: Cu.cloneInto(detail, this.document.defaultView), + }); + this.document.dispatchEvent(event); + } +} |