tor-browser

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

QuickActionsLoaderDefault.sys.mjs (13284B)


      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 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
      6 
      7 const lazy = {};
      8 
      9 ChromeUtils.defineESModuleGetters(lazy, {
     10  ActionsProviderQuickActions:
     11    "moz-src:///browser/components/urlbar/ActionsProviderQuickActions.sys.mjs",
     12  BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
     13  DevToolsShim: "chrome://devtools-startup/content/DevToolsShim.sys.mjs",
     14  ResetProfile: "resource://gre/modules/ResetProfile.sys.mjs",
     15  ScreenshotsUtils: "resource:///modules/ScreenshotsUtils.sys.mjs",
     16  TranslationsParent: "resource://gre/actors/TranslationsParent.sys.mjs",
     17  UrlbarUtils: "moz-src:///browser/components/urlbar/UrlbarUtils.sys.mjs",
     18  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
     19 });
     20 
     21 ChromeUtils.defineLazyGetter(lazy, "logger", () =>
     22  lazy.UrlbarUtils.getLogger({ prefix: "QuickActions" })
     23 );
     24 
     25 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
     26 
     27 if (AppConstants.MOZ_UPDATER) {
     28  XPCOMUtils.defineLazyServiceGetter(
     29    lazy,
     30    "AUS",
     31    "@mozilla.org/updates/update-service;1",
     32    Ci.nsIApplicationUpdateService
     33  );
     34 }
     35 
     36 let openUrlFun = url => () => openUrl(url);
     37 let openUrl = url => {
     38  let window = lazy.BrowserWindowTracker.getTopWindow({
     39    allowFromInactiveWorkspace: true,
     40  });
     41 
     42  if (url.startsWith("about:")) {
     43    window.switchToTabHavingURI(Services.io.newURI(url), true, {
     44      ignoreFragment: "whenComparing",
     45    });
     46  } else {
     47    window.gBrowser.addTab(url, {
     48      inBackground: false,
     49      triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
     50    });
     51  }
     52  return { focusContent: true };
     53 };
     54 
     55 let openAddonsUrl = url => {
     56  return () => {
     57    // bug 1983835 - should this only look for windows on the current
     58    // workspace?
     59    let window = lazy.BrowserWindowTracker.getTopWindow({
     60      allowFromInactiveWorkspace: true,
     61    });
     62    window.BrowserAddonUI.openAddonsMgr(url, { selectTabByViewId: true });
     63  };
     64 };
     65 
     66 // bug 1983835 - should this only look for windows on the current
     67 // workspace?
     68 let currentBrowser = () =>
     69  lazy.BrowserWindowTracker.getTopWindow({ allowFromInactiveWorkspace: true })
     70    ?.gBrowser.selectedBrowser;
     71 // bug 1983835 - should this only look for windows on the current
     72 // workspace?
     73 let currentTab = () =>
     74  lazy.BrowserWindowTracker.getTopWindow({ allowFromInactiveWorkspace: true })
     75    ?.gBrowser.selectedTab;
     76 
     77 ChromeUtils.defineLazyGetter(lazy, "gFluentStrings", function () {
     78  return new Localization(
     79    [
     80      "branding/brand.ftl",
     81      "browser/browser.ftl",
     82      "toolkit/branding/brandings.ftl",
     83    ],
     84    true
     85  );
     86 });
     87 
     88 const DEFAULT_ACTIONS = {
     89  addons: {
     90    l10nCommands: ["quickactions-cmd-addons3"],
     91    icon: "chrome://mozapps/skin/extensions/category-extensions.svg",
     92    label: "quickactions-addons",
     93    onPick: openAddonsUrl("addons://discover/"),
     94    // Hide in base-browser, since we don't want to open extensions
     95    // "recommendations" tab. tor-browser#43864.
     96    disabled: () => true,
     97  },
     98  bookmarks: {
     99    l10nCommands: ["quickactions-cmd-bookmarks", "quickactions-bookmarks2"],
    100    icon: "chrome://browser/skin/bookmark.svg",
    101    label: "quickactions-bookmarks2",
    102    onPick: () => {
    103      lazy.BrowserWindowTracker.getTopWindow({
    104        allowFromInactiveWorkspace: true,
    105      }).top.PlacesCommandHook.showPlacesOrganizer("BookmarksToolbar");
    106    },
    107  },
    108  clear: {
    109    l10nCommands: [
    110      "quickactions-cmd-clearrecenthistory",
    111      "quickactions-clearrecenthistory",
    112    ],
    113    label: "quickactions-clearrecenthistory",
    114    onPick: () => {
    115      lazy.BrowserWindowTracker.getTopWindow({
    116        allowFromInactiveWorkspace: true,
    117      })
    118        .document.getElementById("Tools:Sanitize")
    119        .doCommand();
    120    },
    121    // Disable in permanent private browsing. tor-browser#43864.
    122    // NOTE: This should also be disabled in private windows, but we don't have
    123    // access to a Window element to check. See mozilla bug 1980912.
    124    disabled: () => {
    125      return lazy.PrivateBrowsingUtils.permanentPrivateBrowsing;
    126    },
    127  },
    128  downloads: {
    129    l10nCommands: ["quickactions-cmd-downloads"],
    130    icon: "chrome://browser/skin/downloads/downloads.svg",
    131    label: "quickactions-downloads2",
    132    onPick: openUrlFun("about:downloads"),
    133  },
    134  extensions: {
    135    l10nCommands: ["quickactions-cmd-extensions2"],
    136    icon: "chrome://mozapps/skin/extensions/category-extensions.svg",
    137    label: "quickactions-extensions",
    138    onPick: openAddonsUrl("addons://list/extension"),
    139    // Hide in base-browser since we do not want to encourage users to change
    140    // their extensions/addons. tor-browser#43864.
    141    disabled: () => true,
    142  },
    143  help: {
    144    l10nCommands: ["quickactions-cmd-help"],
    145    icon: "chrome://global/skin/icons/help.svg",
    146    label: "quickactions-help",
    147    // Open the base-browser support/help page, rather than Firefox's.
    148    // tor-browser#43864.
    149    onPick: openUrlFun(
    150      Services.prefs.getStringPref("browser.base-browser-support-url", "")
    151    ),
    152  },
    153  firefoxview: {
    154    l10nCommands: ["quickactions-cmd-firefoxview"],
    155    icon: "chrome://browser/skin/firefox-view.svg",
    156    label: "quickactions-firefoxview",
    157    onPick: () => {
    158      lazy.BrowserWindowTracker.getTopWindow({
    159        allowFromInactiveWorkspace: true,
    160      }).FirefoxViewHandler.openTab();
    161    },
    162    // Hide in base-browser since firefoxview is disabled.
    163    // tor-browser#43864 and tor-browser#42037.
    164    disabled: () => true,
    165  },
    166  inspect: {
    167    l10nCommands: ["quickactions-cmd-inspector2"],
    168    icon: "chrome://devtools/skin/images/open-inspector.svg",
    169    label: "quickactions-inspector2",
    170    isVisible: () => {
    171      // The inspect action is available if:
    172      // 1. DevTools is enabled.
    173      // 2. The user can be considered as a DevTools user.
    174      // 3. The url is not about:devtools-toolbox.
    175      // 4. The inspector is not opened yet on the page.
    176      return (
    177        lazy.DevToolsShim.isEnabled() &&
    178        lazy.DevToolsShim.isDevToolsUser() &&
    179        !currentBrowser()?.currentURI.spec.startsWith(
    180          "about:devtools-toolbox"
    181        ) &&
    182        !lazy.DevToolsShim.hasToolboxForTab(currentTab())
    183      );
    184    },
    185    onPick: openInspector,
    186  },
    187  logins: {
    188    l10nCommands: ["quickactions-cmd-logins"],
    189    label: "quickactions-logins2",
    190    onPick: openUrlFun("about:logins"),
    191    // Disabled in base browser since saved passwords is not well supported in
    192    // Tor Browser, and should be disabled in Mullvad Browser.
    193    // tor-browser#44177.
    194    disabled: () => true,
    195  },
    196  print: {
    197    l10nCommands: ["quickactions-cmd-print"],
    198    label: "quickactions-print2",
    199    icon: "chrome://global/skin/icons/print.svg",
    200    isVisible: () => {
    201      return Services.prefs.getBoolPref("print.enabled");
    202    },
    203    onPick: () => {
    204      lazy.BrowserWindowTracker.getTopWindow({
    205        allowFromInactiveWorkspace: true,
    206      })
    207        .document.getElementById("cmd_print")
    208        .doCommand();
    209    },
    210  },
    211  private: {
    212    l10nCommands: ["quickactions-cmd-private"],
    213    label: "quickactions-private2",
    214    icon: "chrome://global/skin/icons/indicator-private-browsing.svg",
    215    onPick: () => {
    216      lazy.BrowserWindowTracker.getTopWindow({
    217        allowFromInactiveWorkspace: true,
    218      }).OpenBrowserWindow({
    219        private: true,
    220      });
    221    },
    222    // Disable in permanent private browsing. tor-browser#44177.
    223    disabled: () => {
    224      return lazy.PrivateBrowsingUtils.permanentPrivateBrowsing;
    225    },
    226  },
    227  refresh: {
    228    l10nCommands: ["quickactions-cmd-refresh"],
    229    label: "quickactions-refresh",
    230    isVisible: () => lazy.ResetProfile.resetSupported(),
    231    onPick: () => {
    232      lazy.ResetProfile.openConfirmationDialog(
    233        lazy.BrowserWindowTracker.getTopWindow({
    234          allowFromInactiveWorkspace: true,
    235        })
    236      );
    237    },
    238  },
    239  restart: {
    240    l10nCommands: ["quickactions-cmd-restart"],
    241    label: "quickactions-restart",
    242    onPick: restartBrowser,
    243  },
    244  savepdf: {
    245    l10nCommands: ["quickactions-cmd-savepdf2"],
    246    label: "quickactions-savepdf",
    247    icon: "chrome://global/skin/icons/print.svg",
    248    isVisible: () => {
    249      return Services.prefs.getBoolPref("print.enabled");
    250    },
    251    onPick: () => {
    252      // This writes over the users last used printer which we
    253      // should not do. Refactor to launch the print preview with
    254      // custom settings.
    255      let win = lazy.BrowserWindowTracker.getTopWindow({
    256        allowFromInactiveWorkspace: true,
    257      });
    258      Cc["@mozilla.org/gfx/printsettings-service;1"]
    259        .getService(Ci.nsIPrintSettingsService)
    260        .maybeSaveLastUsedPrinterNameToPrefs(
    261          win.PrintUtils.SAVE_TO_PDF_PRINTER
    262        );
    263      win.PrintUtils.startPrintWindow(
    264        win.gBrowser.selectedBrowser.browsingContext,
    265        {}
    266      );
    267    },
    268  },
    269  screenshot: {
    270    l10nCommands: ["quickactions-cmd-screenshot2"],
    271    label: "quickactions-screenshot3",
    272    icon: "chrome://browser/skin/screenshot.svg",
    273    isVisible: () => {
    274      return lazy.ScreenshotsUtils.screenshotsEnabled;
    275    },
    276    onPick: () => {
    277      Services.obs.notifyObservers(
    278        lazy.BrowserWindowTracker.getTopWindow({
    279          allowFromInactiveWorkspace: true,
    280        }),
    281        "menuitem-screenshot",
    282        "QuickActions"
    283      );
    284      return { focusContent: true };
    285    },
    286  },
    287  settings: {
    288    l10nCommands: ["quickactions-cmd-settings2"],
    289    icon: "chrome://global/skin/icons/settings.svg",
    290    label: "quickactions-settings2",
    291    onPick: openUrlFun("about:preferences"),
    292  },
    293  themes: {
    294    l10nCommands: ["quickactions-cmd-themes2"],
    295    icon: "chrome://mozapps/skin/extensions/category-extensions.svg",
    296    label: "quickactions-themes",
    297    onPick: openAddonsUrl("addons://list/theme"),
    298  },
    299  translate: {
    300    l10nCommands: ["quickactions-cmd-translate"],
    301    icon: "chrome://browser/skin/translations.svg",
    302    label: "quickactions-translate",
    303    isVisible: () => {
    304      return Services.prefs.getBoolPref(
    305        "browser.translations.quickAction.enabled",
    306        false
    307      );
    308    },
    309    onPick: async () => {
    310      let url = "about:translations";
    311      let targetLanguage;
    312 
    313      try {
    314        targetLanguage =
    315          await lazy.TranslationsParent.getTopPreferredSupportedToLang();
    316      } catch (error) {
    317        lazy.logger.error(error);
    318      }
    319 
    320      if (targetLanguage) {
    321        const urlObj = new URL(url);
    322        const params = new URLSearchParams();
    323        params.set("trg", targetLanguage);
    324        urlObj.hash = params.toString();
    325        url = urlObj.href;
    326      }
    327 
    328      return openUrl(url);
    329    },
    330  },
    331  update: {
    332    l10nCommands: ["quickactions-cmd-update"],
    333    label: "quickactions-update",
    334    isVisible: () => {
    335      if (!AppConstants.MOZ_UPDATER) {
    336        return false;
    337      }
    338      return (
    339        lazy.AUS.currentState == Ci.nsIApplicationUpdateService.STATE_PENDING
    340      );
    341    },
    342    onPick: restartBrowser,
    343  },
    344  viewsource: {
    345    l10nCommands: ["quickactions-cmd-viewsource2"],
    346    icon: "chrome://global/skin/icons/settings.svg",
    347    label: "quickactions-viewsource2",
    348    isVisible: () => currentBrowser()?.currentURI.scheme !== "view-source",
    349    onPick: () => openUrl("view-source:" + currentBrowser().currentURI.spec),
    350  },
    351 };
    352 
    353 function openInspector() {
    354  lazy.DevToolsShim.showToolboxForTab(
    355    lazy.BrowserWindowTracker.getTopWindow({ allowFromInactiveWorkspace: true })
    356      .gBrowser.selectedTab,
    357    { toolId: "inspector" }
    358  );
    359 }
    360 
    361 // TODO: We likely want a prompt to confirm with the user that they want to restart
    362 // the browser.
    363 function restartBrowser() {
    364  // Notify all windows that an application quit has been requested.
    365  let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
    366    Ci.nsISupportsPRBool
    367  );
    368  Services.obs.notifyObservers(
    369    cancelQuit,
    370    "quit-application-requested",
    371    "restart"
    372  );
    373  // Something aborted the quit process.
    374  if (cancelQuit.data) {
    375    return;
    376  }
    377  // If already in safe mode restart in safe mode.
    378  if (Services.appinfo.inSafeMode) {
    379    Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
    380  } else {
    381    Services.startup.quit(
    382      Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart
    383    );
    384  }
    385 }
    386 
    387 /**
    388 * Loads the default QuickActions.
    389 */
    390 export class QuickActionsLoaderDefault {
    391  // Track the loading of the QuickActions to ensure they aren't loaded multiple times.
    392  static #loadedPromise = null;
    393 
    394  static async load() {
    395    let keys = Object.keys(DEFAULT_ACTIONS);
    396    for (const key of keys) {
    397      let actionData = DEFAULT_ACTIONS[key];
    398      if (actionData.disabled?.()) {
    399        continue;
    400      }
    401      let messages = await lazy.gFluentStrings.formatMessages(
    402        actionData.l10nCommands.map(id => ({ id }))
    403      );
    404      actionData.commands = messages
    405        .map(({ value }) => value.split(",").map(x => x.trim().toLowerCase()))
    406        .flat();
    407      lazy.ActionsProviderQuickActions.addAction(key, actionData);
    408    }
    409  }
    410  static async ensureLoaded() {
    411    if (!this.#loadedPromise) {
    412      this.#loadedPromise = this.load();
    413    }
    414    await this.#loadedPromise;
    415  }
    416 }