Bug 1525718 fix setting private permission when private browsing r=rpl
authorShane Caraveo <scaraveo@mozilla.com>
Thu, 14 Feb 2019 15:52:29 +0000
changeset 460152 5fa1f6433408d804a98025029a3ed38260a81dce
parent 460151 fb6c0d850fa3bac79d61a81fd35346a309e5e5c7
child 460196 2acb22602c60a2380cdd978d6bbdc55ba314604b
child 460207 04cea11a5ecc304925c7f9cce91b7c611621f03e
push id35584
push useropoprus@mozilla.com
push dateThu, 21 Feb 2019 09:28:57 +0000
treeherdermozilla-central@5fa1f6433408 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrpl
bugs1525718
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1525718 fix setting private permission when private browsing r=rpl Setting the permission has to happen after the call to parseManifest so it may be set if the manifest is already cached. Also grant permission when installed from permanent private browsing. Differential Revision: https://phabricator.services.mozilla.com/D18879
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -48,16 +48,17 @@ XPCOMUtils.defineLazyModuleGetters(this,
   ExtensionTelemetry: "resource://gre/modules/ExtensionTelemetry.jsm",
   FileSource: "resource://gre/modules/L10nRegistry.jsm",
   L10nRegistry: "resource://gre/modules/L10nRegistry.jsm",
   Log: "resource://gre/modules/Log.jsm",
   MessageChannel: "resource://gre/modules/MessageChannel.jsm",
   NetUtil: "resource://gre/modules/NetUtil.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   PluralForm: "resource://gre/modules/PluralForm.jsm",
+  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   Schemas: "resource://gre/modules/Schemas.jsm",
   XPIProvider: "resource://gre/modules/addons/XPIProvider.jsm",
 });
 
 // This is used for manipulating jar entry paths, which always use Unix
 // separators.
 XPCOMUtils.defineLazyGetter(
   this, "OSPath", () => {
@@ -706,23 +707,16 @@ class ExtensionData {
         } else if (type.invalid) {
           this.manifestWarning(`Invalid extension permission: ${perm}`);
           continue;
         }
 
         permissions.add(perm);
       }
 
-      // We only want to set permissions if the feature is preffed on
-      // (allowPrivateBrowsingByDefault is false)
-      if (!allowPrivateBrowsingByDefault &&
-          manifest.incognito !== "not_allowed" &&
-          this.isPrivileged && !this.addonData.temporarilyInstalled) {
-        permissions.add("internal:privateBrowsingAllowed");
-      }
 
       if (this.id) {
         // An extension always gets permission to its own url.
         let matcher = new MatchPattern(this.getURL(), {ignorePath: true});
         originPermissions.add(matcher.pattern);
 
         // Apply optional permissions
         let perms = await ExtensionPermissions.get(this.id);
@@ -1885,16 +1879,32 @@ class Extension extends ExtensionData {
       if (this.errors.length) {
         return Promise.reject({errors: this.errors});
       }
 
       if (this.hasShutdown) {
         return;
       }
 
+      // If we're in permanent private browsing and an extension is installed, we
+      // add the permission. Any other situation requires the user to explicitly
+      // enable the permission in about:addons.
+      // Privileged/system extensions get private browsing access automatically,
+      // unless they opt-out by setting "not_allowed".
+      if (!allowPrivateBrowsingByDefault && this.manifest.incognito !== "not_allowed" &&
+          !this.permissions.has("internal:privateBrowsingAllowed")) {
+        if ((PrivateBrowsingUtils.permanentPrivateBrowsing && this.startupReason == "ADDON_INSTALL") ||
+            (this.isPrivileged && !this.addonData.temporarilyInstalled)) {
+          // Add to EP so it is preserved after ADDON_INSTALL.  We don't wait on the add here
+          // since we are pushing the value into this.permissions.  EP will eventually save.
+          ExtensionPermissions.add(this.id, {permissions: ["internal:privateBrowsingAllowed"], origins: []});
+          this.permissions.add("internal:privateBrowsingAllowed");
+        }
+      }
+
       GlobalManager.init(this);
 
       this.initSharedData();
 
       this.policy.active = false;
       this.policy = ExtensionProcessScript.initExtension(this);
       this.policy.extension = this;
 
--- a/toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_background_private_browsing.js
@@ -1,34 +1,81 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
+const {AddonManager} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
+const {ExtensionPermissions} = ChromeUtils.import("resource://gre/modules/ExtensionPermissions.jsm");
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
+AddonTestUtils.usePrivilegedSignatures = false;
+
 add_task(async function test_background_incognito() {
   info("Test background page incognito value with permanent private browsing enabled");
+  await AddonTestUtils.promiseStartupManager();
 
   Services.prefs.setBoolPref("extensions.allowPrivateBrowsingByDefault", false);
   Services.prefs.setBoolPref("browser.privatebrowsing.autostart", true);
   registerCleanupFunction(() => {
     Services.prefs.clearUserPref("browser.privatebrowsing.autostart");
     Services.prefs.clearUserPref("extensions.allowPrivateBrowsingByDefault");
   });
 
+  let extensionId = "@permTest";
+  // We do not need to override incognito here, an extension installed during
+  // permanent private browsing gets the permission during install.
   let extension = ExtensionTestUtils.loadExtension({
-    incognitoOverride: "spanning",
+    useAddonManager: "permanent",
+    manifest: {
+      applications: {
+        gecko: {id: extensionId},
+      },
+    },
     async background() {
       browser.test.assertEq(window, browser.extension.getBackgroundPage(),
                             "Caller should be able to access itself as a background page");
       browser.test.assertEq(window, await browser.runtime.getBackgroundPage(),
                             "Caller should be able to access itself as a background page");
 
       browser.test.assertEq(browser.extension.inIncognitoContext, true,
                             "inIncognitoContext is true for permanent private browsing");
 
-      browser.test.notifyPass("incognito");
+      browser.test.sendMessage("incognito");
     },
   });
 
+  // Startup reason is ADDON_INSTALL
   await extension.startup();
 
-  await extension.awaitFinish("incognito");
+  await extension.awaitMessage("incognito");
+
+  let addon = await AddonManager.getAddonByID(extensionId);
+  await addon.disable();
+
+  // Permission remains when an extension is disabled.
+  let perms = await ExtensionPermissions.get(extensionId);
+  equal(perms.permissions.length, 1, "one permission");
+  equal(perms.permissions[0], "internal:privateBrowsingAllowed", "internal permission present");
+
+  // Startup reason is ADDON_ENABLE, the permission is
+  // not granted in this case, but the extension should
+  // still have permission.
+  await addon.enable();
+  await Promise.all([
+    extension.awaitStartup(),
+    extension.awaitMessage("incognito"),
+  ]);
+
+  // ExtensionPermissions should still have it.
+  perms = await ExtensionPermissions.get(extensionId);
+  equal(perms.permissions.length, 1, "one permission");
+  equal(perms.permissions[0], "internal:privateBrowsingAllowed", "internal permission present");
+
+  // This is the same as uninstall, no permissions after.
   await extension.unload();
+
+  perms = await ExtensionPermissions.get(extensionId);
+  equal(perms.permissions.length, 0, "no permission");
+
+  await AddonTestUtils.promiseShutdownManager();
 });