tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ext-url-overrides.js (7037B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 var { ExtensionParent } = ChromeUtils.importESModule(
      8  "resource://gre/modules/ExtensionParent.sys.mjs"
      9 );
     10 
     11 ChromeUtils.defineESModuleGetters(this, {
     12  AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs",
     13  ExtensionControlledPopup:
     14    "resource:///modules/ExtensionControlledPopup.sys.mjs",
     15  ExtensionSettingsStore:
     16    "resource://gre/modules/ExtensionSettingsStore.sys.mjs",
     17 });
     18 
     19 const STORE_TYPE = "url_overrides";
     20 const NEW_TAB_SETTING_NAME = "newTabURL";
     21 const NEW_TAB_CONFIRMED_TYPE = "newTabNotification";
     22 const NEW_TAB_PRIVATE_ALLOWED = "browser.newtab.privateAllowed";
     23 const NEW_TAB_EXTENSION_CONTROLLED = "browser.newtab.extensionControlled";
     24 
     25 ChromeUtils.defineLazyGetter(this, "newTabPopup", () => {
     26  return new ExtensionControlledPopup({
     27    confirmedType: NEW_TAB_CONFIRMED_TYPE,
     28    observerTopic: "browser-open-newtab-start",
     29    popupnotificationId: "extension-new-tab-notification",
     30    settingType: STORE_TYPE,
     31    settingKey: NEW_TAB_SETTING_NAME,
     32    descriptionId: "extension-new-tab-notification-description",
     33    descriptionMessageId: "newTabControlled.message2",
     34    learnMoreLink: "extension-home",
     35    preferencesLocation: "home-newtabOverride",
     36    preferencesEntrypoint: "addon-manage-newtab-override",
     37    onObserverAdded() {
     38      AboutNewTab.willNotifyUser = true;
     39    },
     40    onObserverRemoved() {
     41      AboutNewTab.willNotifyUser = false;
     42    },
     43    async beforeDisableAddon(popup, win) {
     44      // ExtensionControlledPopup will disable the add-on once this function completes.
     45      // Disabling an add-on should remove the tabs that it has open, but we want
     46      // to open the new New Tab in this tab (which might get closed).
     47      //   1. Replace the tab's URL with about:blank
     48      //   2. Return control to ExtensionControlledPopup once about:blank has loaded
     49      //   3. Once the New Tab URL has changed, replace the tab's URL with the new New Tab URL
     50      let gBrowser = win.gBrowser;
     51      let tab = gBrowser.selectedTab;
     52      await replaceUrlInTab(gBrowser, tab, Services.io.newURI("about:blank"));
     53      Services.obs.addObserver(
     54        {
     55          async observe() {
     56            await replaceUrlInTab(
     57              gBrowser,
     58              tab,
     59              Services.io.newURI(AboutNewTab.newTabURL)
     60            );
     61            // Now that the New Tab is loading, try to open the popup again. This
     62            // will only open the popup if a new extension is controlling the New Tab.
     63            popup.open();
     64            Services.obs.removeObserver(this, "newtab-url-changed");
     65          },
     66        },
     67        "newtab-url-changed"
     68      );
     69    },
     70  });
     71 });
     72 
     73 function setNewTabURL(extensionId, url) {
     74  if (extensionId) {
     75    newTabPopup.addObserver(extensionId);
     76    let policy = ExtensionParent.WebExtensionPolicy.getByID(extensionId);
     77    Services.prefs.setBoolPref(
     78      NEW_TAB_PRIVATE_ALLOWED,
     79      policy && policy.privateBrowsingAllowed
     80    );
     81    Services.prefs.setBoolPref(NEW_TAB_EXTENSION_CONTROLLED, true);
     82  } else {
     83    newTabPopup.removeObserver();
     84    Services.prefs.clearUserPref(NEW_TAB_PRIVATE_ALLOWED);
     85    Services.prefs.clearUserPref(NEW_TAB_EXTENSION_CONTROLLED);
     86  }
     87  if (url) {
     88    AboutNewTab.newTabURL = url;
     89  }
     90 }
     91 
     92 // eslint-disable-next-line mozilla/balanced-listeners
     93 ExtensionParent.apiManager.on(
     94  "extension-setting-changed",
     95  async (eventName, setting) => {
     96    let extensionId, url;
     97    if (setting.type === STORE_TYPE && setting.key === NEW_TAB_SETTING_NAME) {
     98      // If the actual setting has changed in some way, we will have
     99      // setting.item which is what the setting has been changed to.  If
    100      // we have an item, we always want to update the newTabUrl values.
    101      let { item } = setting;
    102      if (item) {
    103        // If we're resetting, id will be undefined.
    104        extensionId = item.id;
    105        url = item.value || item.initialValue;
    106        setNewTabURL(extensionId, url);
    107      }
    108    }
    109  }
    110 );
    111 
    112 async function processSettings(action, id) {
    113  await ExtensionSettingsStore.initialize();
    114  if (ExtensionSettingsStore.hasSetting(id, STORE_TYPE, NEW_TAB_SETTING_NAME)) {
    115    ExtensionSettingsStore[action](id, STORE_TYPE, NEW_TAB_SETTING_NAME);
    116  }
    117 }
    118 
    119 this.urlOverrides = class extends ExtensionAPI {
    120  static async onDisable(id) {
    121    newTabPopup.clearConfirmation(id);
    122    await processSettings("disable", id);
    123  }
    124 
    125  static async onEnabling(id) {
    126    await processSettings("enable", id);
    127  }
    128 
    129  static async onUninstall(id) {
    130    // TODO: This can be removed once bug 1438364 is fixed and all data is cleaned up.
    131    newTabPopup.clearConfirmation(id);
    132    await processSettings("removeSetting", id);
    133  }
    134 
    135  static async onUpdate(id, manifest) {
    136    if (
    137      !manifest.chrome_url_overrides ||
    138      !manifest.chrome_url_overrides.newtab
    139    ) {
    140      await ExtensionSettingsStore.initialize();
    141      if (
    142        ExtensionSettingsStore.hasSetting(id, STORE_TYPE, NEW_TAB_SETTING_NAME)
    143      ) {
    144        ExtensionSettingsStore.removeSetting(
    145          id,
    146          STORE_TYPE,
    147          NEW_TAB_SETTING_NAME
    148        );
    149      }
    150    }
    151  }
    152 
    153  async onManifestEntry() {
    154    let { extension } = this;
    155    let { manifest } = extension;
    156 
    157    if (manifest.chrome_url_overrides.newtab) {
    158      let url = extension.baseURI.resolve(manifest.chrome_url_overrides.newtab);
    159 
    160      await ExtensionSettingsStore.initialize();
    161      let item = await ExtensionSettingsStore.addSetting(
    162        extension.id,
    163        STORE_TYPE,
    164        NEW_TAB_SETTING_NAME,
    165        url,
    166        () => AboutNewTab.newTabURL
    167      );
    168 
    169      // Set the newTabURL to the current value of the setting.
    170      if (item) {
    171        setNewTabURL(item.id, item.value || item.initialValue);
    172      }
    173 
    174      // We need to monitor permission change and update the preferences.
    175      // eslint-disable-next-line mozilla/balanced-listeners
    176      extension.on("add-permissions", async (ignoreEvent, permissions) => {
    177        if (
    178          permissions.permissions.includes("internal:privateBrowsingAllowed")
    179        ) {
    180          let item = await ExtensionSettingsStore.getSetting(
    181            STORE_TYPE,
    182            NEW_TAB_SETTING_NAME
    183          );
    184          if (item && item.id == extension.id) {
    185            Services.prefs.setBoolPref(NEW_TAB_PRIVATE_ALLOWED, true);
    186          }
    187        }
    188      });
    189      // eslint-disable-next-line mozilla/balanced-listeners
    190      extension.on("remove-permissions", async (ignoreEvent, permissions) => {
    191        if (
    192          permissions.permissions.includes("internal:privateBrowsingAllowed")
    193        ) {
    194          let item = await ExtensionSettingsStore.getSetting(
    195            STORE_TYPE,
    196            NEW_TAB_SETTING_NAME
    197          );
    198          if (item && item.id == extension.id) {
    199            Services.prefs.setBoolPref(NEW_TAB_PRIVATE_ALLOWED, false);
    200          }
    201        }
    202      });
    203    }
    204  }
    205 };