forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			232 lines
		
	
	
	
		
			7.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
	
		
			7.2 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/. */
 | 
						|
 | 
						|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(lazy, {
 | 
						|
  AddonStudies: "resource://normandy/lib/AddonStudies.sys.mjs",
 | 
						|
  BranchedAddonStudyAction:
 | 
						|
    "resource://normandy/actions/BranchedAddonStudyAction.sys.mjs",
 | 
						|
  ExperimentManager: "resource://nimbus/lib/ExperimentManager.sys.mjs",
 | 
						|
  PreferenceExperiments:
 | 
						|
    "resource://normandy/lib/PreferenceExperiments.sys.mjs",
 | 
						|
  RecipeRunner: "resource://normandy/lib/RecipeRunner.sys.mjs",
 | 
						|
  RemoteSettingsExperimentLoader:
 | 
						|
    "resource://nimbus/lib/RemoteSettingsExperimentLoader.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
const SHIELD_LEARN_MORE_URL_PREF = "app.normandy.shieldLearnMoreUrl";
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  lazy,
 | 
						|
  "gOptOutStudiesEnabled",
 | 
						|
  "app.shield.optoutstudies.enabled"
 | 
						|
);
 | 
						|
 | 
						|
/**
 | 
						|
 * Class for managing an about: page that Normandy provides. Adapted from
 | 
						|
 * browser/components/pocket/content/AboutPocket.sys.mjs.
 | 
						|
 *
 | 
						|
 * @implements nsIFactory
 | 
						|
 * @implements nsIAboutModule
 | 
						|
 */
 | 
						|
class AboutPage {
 | 
						|
  constructor({ chromeUrl, aboutHost, classID, description, uriFlags }) {
 | 
						|
    this.chromeUrl = chromeUrl;
 | 
						|
    this.aboutHost = aboutHost;
 | 
						|
    this.classID = Components.ID(classID);
 | 
						|
    this.description = description;
 | 
						|
    this.uriFlags = uriFlags;
 | 
						|
  }
 | 
						|
 | 
						|
  getURIFlags() {
 | 
						|
    return this.uriFlags;
 | 
						|
  }
 | 
						|
 | 
						|
  newChannel(uri, loadInfo) {
 | 
						|
    const newURI = Services.io.newURI(this.chromeUrl);
 | 
						|
    const channel = Services.io.newChannelFromURIWithLoadInfo(newURI, loadInfo);
 | 
						|
    channel.originalURI = uri;
 | 
						|
 | 
						|
    if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
 | 
						|
      const principal = Services.scriptSecurityManager.createContentPrincipal(
 | 
						|
        uri,
 | 
						|
        {}
 | 
						|
      );
 | 
						|
      channel.owner = principal;
 | 
						|
    }
 | 
						|
    return channel;
 | 
						|
  }
 | 
						|
}
 | 
						|
AboutPage.prototype.QueryInterface = ChromeUtils.generateQI(["nsIAboutModule"]);
 | 
						|
 | 
						|
/**
 | 
						|
 * The module exported by this file.
 | 
						|
 */
 | 
						|
export let AboutPages = {};
 | 
						|
 | 
						|
/**
 | 
						|
 * 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(AboutPages, "aboutStudies", () => {
 | 
						|
  const aboutStudies = new AboutPage({
 | 
						|
    chromeUrl: "resource://normandy-content/about-studies/about-studies.html",
 | 
						|
    aboutHost: "studies",
 | 
						|
    classID: "{6ab96943-a163-482c-9622-4faedc0e827f}",
 | 
						|
    description: "Shield Study Listing",
 | 
						|
    uriFlags:
 | 
						|
      Ci.nsIAboutModule.ALLOW_SCRIPT |
 | 
						|
      Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
 | 
						|
      Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD |
 | 
						|
      Ci.nsIAboutModule.IS_SECURE_CHROME_UI,
 | 
						|
  });
 | 
						|
 | 
						|
  // Extra methods for about:study-specific behavior.
 | 
						|
  Object.assign(aboutStudies, {
 | 
						|
    getAddonStudyList() {
 | 
						|
      return lazy.AddonStudies.getAll();
 | 
						|
    },
 | 
						|
 | 
						|
    getPreferenceStudyList() {
 | 
						|
      return lazy.PreferenceExperiments.getAll();
 | 
						|
    },
 | 
						|
 | 
						|
    getMessagingSystemList() {
 | 
						|
      return lazy.ExperimentManager.store.getAll();
 | 
						|
    },
 | 
						|
 | 
						|
    async optInToExperiment(data) {
 | 
						|
      try {
 | 
						|
        await lazy.RemoteSettingsExperimentLoader.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("ShieldFrame")
 | 
						|
            .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;
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Disable an active add-on study and remove its add-on.
 | 
						|
     * @param {String} recipeId the id of the addon to remove
 | 
						|
     * @param {String} reason the reason for removal
 | 
						|
     */
 | 
						|
    async removeAddonStudy(recipeId, reason) {
 | 
						|
      try {
 | 
						|
        const action = new lazy.BranchedAddonStudyAction();
 | 
						|
        await action.unenroll(recipeId, reason);
 | 
						|
      } catch (err) {
 | 
						|
        // If the exception was that the study was already removed, that's ok.
 | 
						|
        // If not, rethrow the error.
 | 
						|
        if (!err.toString().includes("already inactive")) {
 | 
						|
          throw err;
 | 
						|
        }
 | 
						|
      } finally {
 | 
						|
        // Update any open tabs with the new study list now that it has changed,
 | 
						|
        // even if the above failed.
 | 
						|
        this.getAddonStudyList().then(list =>
 | 
						|
          this._sendToAll("Shield:UpdateAddonStudyList", list)
 | 
						|
        );
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Disable an active preference study.
 | 
						|
     * @param {String} experimentName the name of the experiment to remove
 | 
						|
     * @param {String} reason the reason for removal
 | 
						|
     */
 | 
						|
    async removePreferenceStudy(experimentName, reason) {
 | 
						|
      try {
 | 
						|
        await lazy.PreferenceExperiments.stop(experimentName, {
 | 
						|
          reason,
 | 
						|
          caller: "AboutPages.removePreferenceStudy",
 | 
						|
        });
 | 
						|
      } catch (err) {
 | 
						|
        // If the exception was that the study was already removed, that's ok.
 | 
						|
        // If not, rethrow the error.
 | 
						|
        if (!err.toString().includes("already expired")) {
 | 
						|
          throw err;
 | 
						|
        }
 | 
						|
      } finally {
 | 
						|
        // Update any open tabs with the new study list now that it has changed,
 | 
						|
        // even if the above failed.
 | 
						|
        this.getPreferenceStudyList().then(list =>
 | 
						|
          this._sendToAll("Shield:UpdatePreferenceStudyList", list)
 | 
						|
        );
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    async removeMessagingSystemExperiment(slug, reason) {
 | 
						|
      lazy.ExperimentManager.unenroll(slug, reason);
 | 
						|
      this._sendToAll(
 | 
						|
        "Shield:UpdateMessagingSystemExperimentList",
 | 
						|
        lazy.ExperimentManager.store.getAll()
 | 
						|
      );
 | 
						|
    },
 | 
						|
 | 
						|
    openDataPreferences() {
 | 
						|
      const browserWindow =
 | 
						|
        Services.wm.getMostRecentWindow("navigator:browser");
 | 
						|
      browserWindow.openPreferences("privacy-reports");
 | 
						|
    },
 | 
						|
 | 
						|
    getShieldLearnMoreHref() {
 | 
						|
      return Services.urlFormatter.formatURLPref(SHIELD_LEARN_MORE_URL_PREF);
 | 
						|
    },
 | 
						|
  });
 | 
						|
 | 
						|
  return aboutStudies;
 | 
						|
});
 |