mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	Doing this helps with code organization and keeping related things together, further shrinking the list of custom component-specific code in BrowserGlue.sys.mjs . Differential Revision: https://phabricator.services.mozilla.com/D244427
		
			
				
	
	
		
			277 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
	
		
			10 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 { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
 | 
						|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | 
						|
 | 
						|
const PRIVATE_BROWSING_BINARY = "private_browsing.exe";
 | 
						|
// Index of Private Browsing icon in private_browsing.exe
 | 
						|
// Must line up with IDI_PBICON_PB_PB_EXE in nsNativeAppSupportWin.h.
 | 
						|
const PRIVATE_BROWSING_EXE_ICON_INDEX = 1;
 | 
						|
const PREF_PRIVATE_BROWSING_SHORTCUT_CREATED =
 | 
						|
  "browser.privacySegmentation.createdShortcut";
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
XPCOMUtils.defineLazyServiceGetters(lazy, {
 | 
						|
  BrowserHandler: ["@mozilla.org/browser/clh;1", "nsIBrowserHandler"],
 | 
						|
  profileService: [
 | 
						|
    "@mozilla.org/toolkit/profile-service;1",
 | 
						|
    "nsIToolkitProfileService",
 | 
						|
  ],
 | 
						|
});
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(lazy, {
 | 
						|
  FirefoxBridgeExtensionUtils:
 | 
						|
    "resource:///modules/FirefoxBridgeExtensionUtils.sys.mjs",
 | 
						|
  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
 | 
						|
  ShellService: "resource:///modules/ShellService.sys.mjs",
 | 
						|
  WindowsLaunchOnLogin: "resource://gre/modules/WindowsLaunchOnLogin.sys.mjs",
 | 
						|
  WindowsGPOParser: "resource://gre/modules/policies/WindowsGPOParser.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
ChromeUtils.defineLazyGetter(lazy, "log", () => {
 | 
						|
  let { ConsoleAPI } = ChromeUtils.importESModule(
 | 
						|
    "resource://gre/modules/Console.sys.mjs"
 | 
						|
  );
 | 
						|
  let consoleOptions = {
 | 
						|
    // tip: set maxLogLevel to "debug" and use lazy.log.debug() to create
 | 
						|
    // detailed messages during development. See LOG_LEVELS in Console.sys.mjs
 | 
						|
    // for details.
 | 
						|
    maxLogLevel: "error",
 | 
						|
    maxLogLevelPref: "browser.policies.loglevel",
 | 
						|
    prefix: "StartupOSIntegration.sys.mjs",
 | 
						|
  };
 | 
						|
  return new ConsoleAPI(consoleOptions);
 | 
						|
});
 | 
						|
 | 
						|
function WindowsRegPoliciesGetter(wrk, root, regLocation) {
 | 
						|
  wrk.open(root, regLocation, wrk.ACCESS_READ);
 | 
						|
  let policies;
 | 
						|
  if (wrk.hasChild("Mozilla\\" + Services.appinfo.name)) {
 | 
						|
    policies = lazy.WindowsGPOParser.readPolicies(wrk, policies);
 | 
						|
  }
 | 
						|
  wrk.close();
 | 
						|
  return policies;
 | 
						|
}
 | 
						|
 | 
						|
export let StartupOSIntegration = {
 | 
						|
  isPrivateBrowsingAllowedInRegistry() {
 | 
						|
    // If there is an attempt to open Private Browsing before
 | 
						|
    // EnterprisePolicies are initialized the Windows registry
 | 
						|
    // can be checked to determine if it is enabled
 | 
						|
    if (Services.policies.status > Ci.nsIEnterprisePolicies.UNINITIALIZED) {
 | 
						|
      // Yield to policies engine if initialized
 | 
						|
      let privateAllowed = Services.policies.isAllowed("privatebrowsing");
 | 
						|
      lazy.log.debug(
 | 
						|
        `Yield to initialized policies engine: Private Browsing Allowed = ${privateAllowed}`
 | 
						|
      );
 | 
						|
      return privateAllowed;
 | 
						|
    }
 | 
						|
    if (AppConstants.platform !== "win") {
 | 
						|
      // Not using Windows so no registry, return true
 | 
						|
      lazy.log.debug(
 | 
						|
        "AppConstants.platform is not 'win': Private Browsing allowed"
 | 
						|
      );
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    // If all other checks fail only then do we check registry
 | 
						|
    let wrk = Cc["@mozilla.org/windows-registry-key;1"].createInstance(
 | 
						|
      Ci.nsIWindowsRegKey
 | 
						|
    );
 | 
						|
    let regLocation = "SOFTWARE\\Policies";
 | 
						|
    let userPolicies, machinePolicies;
 | 
						|
    // Only check HKEY_LOCAL_MACHINE if not in testing
 | 
						|
    if (!Cu.isInAutomation) {
 | 
						|
      machinePolicies = WindowsRegPoliciesGetter(
 | 
						|
        wrk,
 | 
						|
        wrk.ROOT_KEY_LOCAL_MACHINE,
 | 
						|
        regLocation
 | 
						|
      );
 | 
						|
    }
 | 
						|
    // Check machine policies before checking user policies
 | 
						|
    // HKEY_LOCAL_MACHINE supersedes HKEY_CURRENT_USER so only check
 | 
						|
    // HKEY_CURRENT_USER if the registry key is not present in
 | 
						|
    // HKEY_LOCAL_MACHINE at all
 | 
						|
    if (machinePolicies && "DisablePrivateBrowsing" in machinePolicies) {
 | 
						|
      lazy.log.debug(
 | 
						|
        `DisablePrivateBrowsing in HKEY_LOCAL_MACHINE is ${machinePolicies.DisablePrivateBrowsing}`
 | 
						|
      );
 | 
						|
      return !(machinePolicies.DisablePrivateBrowsing === 1);
 | 
						|
    }
 | 
						|
    userPolicies = WindowsRegPoliciesGetter(
 | 
						|
      wrk,
 | 
						|
      wrk.ROOT_KEY_CURRENT_USER,
 | 
						|
      regLocation
 | 
						|
    );
 | 
						|
    if (userPolicies && "DisablePrivateBrowsing" in userPolicies) {
 | 
						|
      lazy.log.debug(
 | 
						|
        `DisablePrivateBrowsing in HKEY_CURRENT_USER is ${userPolicies.DisablePrivateBrowsing}`
 | 
						|
      );
 | 
						|
      return !(userPolicies.DisablePrivateBrowsing === 1);
 | 
						|
    }
 | 
						|
    // Private browsing allowed if no registry entry exists
 | 
						|
    lazy.log.debug(
 | 
						|
      "No DisablePrivateBrowsing registry entry: Private Browsing allowed"
 | 
						|
    );
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  checkForLaunchOnLogin() {
 | 
						|
    // We only support launch on login on Windows at the moment.
 | 
						|
    if (AppConstants.platform != "win") {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    let launchOnLoginPref = "browser.startup.windowsLaunchOnLogin.enabled";
 | 
						|
    if (!lazy.profileService.startWithLastProfile) {
 | 
						|
      // If we don't start with last profile, the user
 | 
						|
      // likely sees the profile selector on launch.
 | 
						|
      if (Services.prefs.getBoolPref(launchOnLoginPref)) {
 | 
						|
        Glean.launchOnLogin.lastProfileDisableStartup.record();
 | 
						|
        // Disable launch on login messaging if we are disabling the
 | 
						|
        // feature.
 | 
						|
        Services.prefs.setBoolPref(
 | 
						|
          "browser.startup.windowsLaunchOnLogin.disableLaunchOnLoginPrompt",
 | 
						|
          true
 | 
						|
        );
 | 
						|
      }
 | 
						|
      // To reduce confusion when running multiple Gecko profiles,
 | 
						|
      // delete launch on login shortcuts and registry keys so that
 | 
						|
      // users are not presented with the outdated profile selector
 | 
						|
      // dialog.
 | 
						|
      lazy.WindowsLaunchOnLogin.removeLaunchOnLogin();
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // Note: currently only invoked on Windows and macOS.
 | 
						|
  async onStartupIdle() {
 | 
						|
    // Catch and report exceptions, including async rejections:
 | 
						|
    let safeCall = async fn => {
 | 
						|
      try {
 | 
						|
        await fn();
 | 
						|
      } catch (ex) {
 | 
						|
        console.error(ex);
 | 
						|
      }
 | 
						|
    };
 | 
						|
    // Note that we explicitly do not await calls to `safeCall` as
 | 
						|
    // these individual calls are independent and can run without
 | 
						|
    // waiting for each other.
 | 
						|
 | 
						|
    // Currently we only support Firefox bridge on Windows and macOS.
 | 
						|
    safeCall(() => this.ensureBridgeRegistered());
 | 
						|
 | 
						|
    if (AppConstants.platform == "win") {
 | 
						|
      if (Services.sysinfo.getProperty("hasWinPackageId")) {
 | 
						|
        safeCall(() => this.maybePinMSIXToStartMenu());
 | 
						|
      }
 | 
						|
      safeCall(() => this.ensurePrivateBrowsingShortcutExists());
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  async ensureBridgeRegistered() {
 | 
						|
    if (!Services.prefs.getBoolPref("browser.firefoxbridge.enabled", false)) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    let { defaultProfile, currentProfile } = lazy.profileService;
 | 
						|
    if (defaultProfile && currentProfile == defaultProfile) {
 | 
						|
      await lazy.FirefoxBridgeExtensionUtils.ensureRegistered();
 | 
						|
    } else {
 | 
						|
      lazy.log.debug(
 | 
						|
        "FirefoxBridgeExtensionUtils failed to register due to non-default current profile."
 | 
						|
      );
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // Silently pin Firefox to the start menu on first run when using MSIX on a
 | 
						|
  // new profile.
 | 
						|
  // If not first run, check if Firefox is no longer pinned to the Start Menu
 | 
						|
  // when it previously was and send telemetry.
 | 
						|
  async maybePinMSIXToStartMenu() {
 | 
						|
    if (!Services.sysinfo.getProperty("hasWinPackageId")) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (
 | 
						|
      lazy.BrowserHandler.firstRunProfile &&
 | 
						|
      (await lazy.ShellService.doesAppNeedStartMenuPin())
 | 
						|
    ) {
 | 
						|
      await lazy.ShellService.pinToStartMenu();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    await lazy.ShellService.recordWasPreviouslyPinnedToStartMenu();
 | 
						|
  },
 | 
						|
 | 
						|
  // Ensure a Private Browsing Shortcut exists. This is needed in case
 | 
						|
  // a user tries to use Windows functionality to pin our Private Browsing
 | 
						|
  // mode icon to the Taskbar (eg: the "Pin to Taskbar" context menu item).
 | 
						|
  // This is also created by the installer, but it's possible that a user
 | 
						|
  // has removed it, or is running out of a zip build. The consequences of not
 | 
						|
  // having a Shortcut for this are that regular Firefox will be pinned instead
 | 
						|
  // of the Private Browsing version -- so it's quite important we do our best
 | 
						|
  // to make sure one is available.
 | 
						|
  // See https://bugzilla.mozilla.org/show_bug.cgi?id=1762994 for additional
 | 
						|
  // background.
 | 
						|
  async ensurePrivateBrowsingShortcutExists() {
 | 
						|
    if (
 | 
						|
      // If the feature is disabled, don't do this.
 | 
						|
      !Services.prefs.getBoolPref(
 | 
						|
        "browser.privateWindowSeparation.enabled",
 | 
						|
        true
 | 
						|
      ) ||
 | 
						|
      // We don't want a shortcut if it's been disabled, eg: by enterprise policy.
 | 
						|
      !lazy.PrivateBrowsingUtils.enabled ||
 | 
						|
      // Private Browsing shortcuts for packaged builds come with the package,
 | 
						|
      // if they exist at all. We shouldn't try to create our own.
 | 
						|
      Services.sysinfo.getProperty("hasWinPackageId") ||
 | 
						|
      // If we've ever done this successfully before, don't try again. The
 | 
						|
      // user may have deleted the shortcut, and we don't want to force it
 | 
						|
      // on them.
 | 
						|
      Services.prefs.getBoolPref(PREF_PRIVATE_BROWSING_SHORTCUT_CREATED, false)
 | 
						|
    ) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let shellService = Cc["@mozilla.org/browser/shell-service;1"].getService(
 | 
						|
      Ci.nsIWindowsShellService
 | 
						|
    );
 | 
						|
    let winTaskbar = Cc["@mozilla.org/windows-taskbar;1"].getService(
 | 
						|
      Ci.nsIWinTaskbar
 | 
						|
    );
 | 
						|
 | 
						|
    if (
 | 
						|
      !(await shellService.hasPinnableShortcut(
 | 
						|
        winTaskbar.defaultPrivateGroupId,
 | 
						|
        true
 | 
						|
      ))
 | 
						|
    ) {
 | 
						|
      let appdir = Services.dirsvc.get("GreD", Ci.nsIFile);
 | 
						|
      let exe = appdir.clone();
 | 
						|
      exe.append(PRIVATE_BROWSING_BINARY);
 | 
						|
      let strings = new Localization(
 | 
						|
        ["branding/brand.ftl", "browser/browser.ftl"],
 | 
						|
        true
 | 
						|
      );
 | 
						|
      let [desc] = await strings.formatValues([
 | 
						|
        "private-browsing-shortcut-text-2",
 | 
						|
      ]);
 | 
						|
      await shellService.createShortcut(
 | 
						|
        exe,
 | 
						|
        [],
 | 
						|
        desc,
 | 
						|
        exe,
 | 
						|
        // The code we're calling indexes from 0 instead of 1
 | 
						|
        PRIVATE_BROWSING_EXE_ICON_INDEX - 1,
 | 
						|
        winTaskbar.defaultPrivateGroupId,
 | 
						|
        "Programs",
 | 
						|
        desc + ".lnk",
 | 
						|
        appdir
 | 
						|
      );
 | 
						|
    }
 | 
						|
    // We always set this as long as no exception has been thrown. This
 | 
						|
    // ensure that it is `true` both if we created one because it didn't
 | 
						|
    // exist, or if it already existed (most likely because it was created
 | 
						|
    // by the installer). This avoids the need to call `hasPinnableShortcut`
 | 
						|
    // again, which necessarily does pointless I/O.
 | 
						|
    Services.prefs.setBoolPref(PREF_PRIVATE_BROWSING_SHORTCUT_CREATED, true);
 | 
						|
  },
 | 
						|
};
 |