Bug 910172 - Refactor XPIProvider.importPermissions out to a reusable JSM. r=Mossop
authorBlair McBride <bmcbride@mozilla.com>
Thu, 10 Oct 2013 14:30:34 +1300
changeset 164130 cd6752c496fda851ac5f0f4cf5c40f42e32a249d
parent 164129 00955d61cc946eaa1e69e5025e646c0cc5b8d1b2
child 164131 6e889bf97a591a8d4eed629563221b9a72486b9e
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMossop
bugs910172
milestone27.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 910172 - Refactor XPIProvider.importPermissions out to a reusable JSM. r=Mossop
toolkit/modules/PermissionsUtils.jsm
toolkit/modules/moz.build
toolkit/modules/tests/xpcshell/test_PermissionsUtils.js
toolkit/modules/tests/xpcshell/xpcshell.ini
toolkit/mozapps/extensions/XPIProvider.jsm
new file mode 100644
--- /dev/null
+++ b/toolkit/modules/PermissionsUtils.jsm
@@ -0,0 +1,79 @@
+// 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/.
+
+this.EXPORTED_SYMBOLS = ["PermissionsUtils"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+
+let gImportedPrefBranches = new Set();
+
+function importPrefBranch(aPrefBranch, aPermission, aAction) {
+  let list = Services.prefs.getChildList(aPrefBranch, {});
+
+  for (let pref of list) {
+    let hosts = "";
+    try {
+      hosts = Services.prefs.getCharPref(pref);
+    } catch (e) {}
+
+    if (!hosts)
+      continue;
+
+    hosts = hosts.split(",");
+
+    for (let host of hosts) {
+      try {
+        let uri = Services.io.newURI("http://" + host, null, null);
+        Services.perms.add(uri, aPermission, aAction);
+      } catch (e) {}
+    }
+
+    Services.prefs.setCharPref(pref, "");
+  }
+}
+
+
+let PermissionsUtils = {
+  /**
+   * Import permissions from perferences to the Permissions Manager. After being
+   * imported, all processed permissions will be set to an empty string.
+   * Perferences are only processed once during the application's
+   * lifetime - it's safe to call this multiple times without worrying about
+   * doing unnecessary work, as the preferences branch will only be processed
+   * the first time.
+   *
+   * @param aPrefBranch  Preferences branch to import from. The preferences
+   *                     under this branch can specify whitelist (ALLOW_ACTION)
+   *                     or blacklist (DENY_ACTION) additions using perference
+   *                     names of the form:
+   *                     * <BRANCH>.whitelist.add.<ID>
+   *                     * <BRANCH>.blacklist.add.<ID>
+   *                     Where <ID> can be any valid preference name.
+   *                     The value is expected to be a comma separated list of
+   *                     host named. eg:
+   *                     * something.example.com
+   *                     * foo.exmaple.com,bar.example.com
+   *
+   * @param aPermission Permission name to be passsed to the Permissions
+   *                    Manager.
+   */
+  importFromPrefs: function(aPrefBranch, aPermission) {
+    if (!aPrefBranch.endsWith("."))
+      aPrefBranch += ".";
+
+    // Ensure we only import this pref branch once.
+    if (gImportedPrefBranches.has(aPrefBranch))
+     return;
+
+    importPrefBranch(aPrefBranch + "whitelist.add", aPermission,
+                     Services.perms.ALLOW_ACTION);
+    importPrefBranch(aPrefBranch + "blacklist.add", aPermission,
+                     Services.perms.DENY_ACTION);
+
+    gImportedPrefBranches.add(aPrefBranch);
+  }
+};
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -14,16 +14,17 @@ EXTRA_JS_MODULES += [
     'FileUtils.jsm',
     'Finder.jsm',
     'Geometry.jsm',
     'Http.jsm',
     'InlineSpellChecker.jsm',
     'LoadContextInfo.jsm',
     'NewTabUtils.jsm',
     'PageMenu.jsm',
+    'PermissionsUtils.jsm',
     'PopupNotifications.jsm',
     'Preferences.jsm',
     'PrivateBrowsingUtils.jsm',
     'Promise.jsm',
     'PropertyListUtils.jsm',
     'RemoteAddonsChild.jsm',
     'RemoteAddonsParent.jsm',
     'RemoteController.jsm',
new file mode 100644
--- /dev/null
+++ b/toolkit/modules/tests/xpcshell/test_PermissionsUtils.js
@@ -0,0 +1,58 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// Tests that PerrmissionsUtils.jsm works as expected, including:
+// * PermissionsUtils.importfromPrefs()
+//      <ROOT>.[whitelist|blacklist].add preferences are emptied when
+//       converted into permissions on startup.
+
+
+const PREF_ROOT = "testpermissions.";
+const TEST_PERM = "text-permission";
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/PermissionsUtils.jsm");
+
+function run_test() {
+  test_importfromPrefs();
+}
+
+
+function test_importfromPrefs() {
+  // Create own preferences to test
+  Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.EMPTY", "");
+  Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.EMPTY2", ",");
+  Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.TEST", "whitelist.example.com");
+  Services.prefs.setCharPref(PREF_ROOT + "whitelist.add.TEST2", "whitelist2-1.example.com,whitelist2-2.example.com");
+  Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.EMPTY", "");
+  Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.TEST", "blacklist.example.com,");
+  Services.prefs.setCharPref(PREF_ROOT + "blacklist.add.TEST2", ",blacklist2-1.example.com,blacklist2-2.example.com");
+
+  // Import them
+  PermissionsUtils.importFromPrefs(PREF_ROOT, TEST_PERM);
+
+  // Get list of preferences to check
+  let preferences = Services.prefs.getChildList(PREF_ROOT, {});
+
+  // Check preferences were emptied
+  for (let pref of preferences) {
+    do_check_eq(Services.prefs.getCharPref(pref), "");
+  }
+
+  // Check they were imported into the permissions manager
+  let whitelisted = ["whitelist.example.com",
+                     "whitelist2-1.example.com",
+                     "whitelist2-2.example.com"];
+  let blacklisted = ["blacklist.example.com",
+                     "blacklist2-1.example.com",
+                     "blacklist2-2.example.com"];
+  for (let url of whitelisted) {
+    let uri = Services.io.newURI("http://" + url, null, null);
+    do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.ALLOW_ACTION);
+  }
+  for (let url of blacklisted) {
+    let uri = Services.io.newURI("http://" + url, null, null);
+    do_check_eq(Services.perms.testPermission(uri, TEST_PERM), Services.perms.DENY_ACTION);
+  }
+}
--- a/toolkit/modules/tests/xpcshell/xpcshell.ini
+++ b/toolkit/modules/tests/xpcshell/xpcshell.ini
@@ -5,16 +5,17 @@ support-files =
   propertyLists/bug710259_propertyListBinary.plist
   propertyLists/bug710259_propertyListXML.plist
   chromeappsstore.sqlite
 
 [test_AsyncShutdown.js]
 [test_dict.js]
 [test_FileUtils.js]
 [test_Http.js]
+[test_PermissionsUtils.js]
 [test_Preferences.js]
 [test_Promise.js]
 [test_propertyListsUtils.js]
 [test_readCertPrefs.js]
 [test_Services.js]
 [test_sqlite.js]
 [test_task.js]
 [test_TelemetryTimestamps.js]
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -20,16 +20,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser",
                                   "resource://gre/modules/ChromeManifestParser.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PermissionsUtils",
+                                  "resource://gre/modules/PermissionsUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "ChromeRegistry",
                                    "@mozilla.org/chrome/chrome-registry;1",
                                    "nsIChromeRegistry");
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "ResProtocolHandler",
                                    "@mozilla.org/network/protocol;1?name=resource",
@@ -52,18 +54,17 @@ const PREF_EM_UPDATE_URL              = 
 const PREF_EM_UPDATE_BACKGROUND_URL   = "extensions.update.background.url";
 const PREF_EM_ENABLED_ADDONS          = "extensions.enabledAddons";
 const PREF_EM_EXTENSION_FORMAT        = "extensions.";
 const PREF_EM_ENABLED_SCOPES          = "extensions.enabledScopes";
 const PREF_EM_AUTO_DISABLED_SCOPES    = "extensions.autoDisableScopes";
 const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
-const PREF_XPI_WHITELIST_PERMISSIONS  = "xpinstall.whitelist.add";
-const PREF_XPI_BLACKLIST_PERMISSIONS  = "xpinstall.blacklist.add";
+const PREF_XPI_PERMISSIONS_BRANCH     = "xpinstall.";
 const PREF_XPI_UNPACK                 = "extensions.alwaysUnpack";
 const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 const PREF_INSTALL_DISTRO_ADDONS      = "extensions.installDistroAddons";
 const PREF_BRANCH_INSTALLED_ADDON     = "extensions.installedDistroAddon.";
 const PREF_SHOWN_SELECTION_UI         = "extensions.shownSelectionUI";
 
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
 const PREF_EM_MIN_COMPAT_PLATFORM_VERSION = "extensions.minCompatiblePlatformVersion";
@@ -3123,36 +3124,18 @@ var XPIProvider = {
     return changed;
   },
 
   /**
    * Imports the xpinstall permissions from preferences into the permissions
    * manager for the user to change later.
    */
   importPermissions: function XPI_importPermissions() {
-    function importList(aPrefBranch, aAction) {
-      let list = Services.prefs.getChildList(aPrefBranch, {});
-      list.forEach(function(aPref) {
-        let hosts = Prefs.getCharPref(aPref, "");
-        if (!hosts)
-          return;
-
-        hosts.split(",").forEach(function(aHost) {
-          Services.perms.add(NetUtil.newURI("http://" + aHost), XPI_PERMISSION,
-                             aAction);
-        });
-
-        Services.prefs.setCharPref(aPref, "");
-      });
-    }
-
-    importList(PREF_XPI_WHITELIST_PERMISSIONS,
-               Ci.nsIPermissionManager.ALLOW_ACTION);
-    importList(PREF_XPI_BLACKLIST_PERMISSIONS,
-               Ci.nsIPermissionManager.DENY_ACTION);
+    PermissionsUtils.importFromPrefs(PREF_XPI_PERMISSIONS_BRANCH,
+                                     XPI_PERMISSION);
   },
 
   /**
    * Checks for any changes that have occurred since the last time the
    * application was launched.
    *
    * @param  aAppChanged
    *         A tri-state value. Undefined means the current profile was created