Bug 796217 - Refactor Webapps.jsm and related files - Part 2: refactor PermissionTable.jsm [r=ddhal]
authorFabrice Desré <fabrice@mozilla.com>
Tue, 02 Oct 2012 22:38:06 -0700
changeset 109007 eb6641924764365f079427c8213ea783e1a702a6
parent 109006 2cc0da49ccb581d6f25e1db5e085c98ce4902c39
child 109008 8694a4aa91cf9596736f3c263f0f4e5a22c430d4
push id23602
push useremorley@mozilla.com
push dateWed, 03 Oct 2012 12:57:12 +0000
treeherdermozilla-central@5ac283a12f02 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersddhal
bugs796217
milestone18.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 796217 - Refactor Webapps.jsm and related files - Part 2: refactor PermissionTable.jsm [r=ddhal]
dom/apps/src/AppsUtils.jsm
dom/apps/src/Makefile.in
dom/apps/src/PermissionsInstaller.jsm
dom/apps/src/PermissionsTable.jsm
dom/apps/src/Webapps.jsm
--- a/dom/apps/src/AppsUtils.jsm
+++ b/dom/apps/src/AppsUtils.jsm
@@ -171,16 +171,37 @@ let AppsUtils = {
 
     for (let localeName in aManifest.locales) {
       if (checkAbsoluteEntryPoints(aManifest.locales[localeName].entry_points)) {
         return false;
       }
     }
 
     return true;
+  },
+
+  /**
+ * Determine the type of app (app, privileged, certified)
+ * that is installed by the manifest
+ * @param object aManifest
+ * @returns integer
+ **/
+  getAppManifestStatus: function getAppManifestStatus(aManifest) {
+    let type = aManifest.type || "web";
+
+    switch(type) {
+    case "web":
+      return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
+    case "privileged":
+      return Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
+    case "certified":
+      return Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
+    default:
+      throw new Error("Webapps.jsm: Undetermined app manifest type");
+    }
   }
 }
 
 /**
  * Helper object to access manifest information with locale support
  */
 let ManifestHelper = function(aManifest, aOrigin) {
   this._origin = Services.io.newURI(aOrigin, null, null);
--- a/dom/apps/src/Makefile.in
+++ b/dom/apps/src/Makefile.in
@@ -16,17 +16,17 @@ EXTRA_COMPONENTS = \
   $(NULL)
 
 EXTRA_PP_COMPONENTS = \
   Webapps.js \
   $(NULL)
 
 EXTRA_PP_JS_MODULES += \
   Webapps.jsm \
-  AppsServiceChild.jsm \
-  AppsUtils.jsm \
   $(NULL)
 
 EXTRA_JS_MODULES += \
-  PermissionsTable.jsm \
+  AppsServiceChild.jsm \
+  AppsUtils.jsm \
+  PermissionsInstaller.jsm \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
rename from dom/apps/src/PermissionsTable.jsm
rename to dom/apps/src/PermissionsInstaller.jsm
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsInstaller.jsm
@@ -1,30 +1,49 @@
 /* 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/. */
 
 "use strict";
 
 const Ci = Components.interfaces;
+const Cu = Components.utils;
 
-var EXPORTED_SYMBOLS = ["PermissionsTable",
-                        "UNKNOWN_ACTION",
-                        "ALLOW_ACTION",
-                        "DENY_ACTION",
-                        "PROMPT_ACTION",
-                        "AllPossiblePermissions",
-                        "mapSuffixes",
-                       ];
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppsUtils.jsm");
+
+var EXPORTED_SYMBOLS = ["PermissionsInstaller"];
 
 const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
 const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
 const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
 const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
 
+// Permission access flags
+const READONLY = "readonly";
+const CREATEONLY = "createonly";
+const READCREATE = "readcreate";
+const READWRITE = "readwrite";
+
+const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "PermSettings",
+                                   "@mozilla.org/permissionSettings;1",
+                                   "nsIDOMPermissionSettings");
+
+XPCOMUtils.defineLazyServiceGetter(this,
+                                   "permissionManager",
+                                   "@mozilla.org/permissionmanager;1",
+                                   "nsIPermissionManager");
+
+function debug(aMsg) {
+  //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
+}
+
 /**
  * Converts ['read', 'write'] to ['contacts-read', 'contacts-write'], etc...
  * @param string aPermName
  * @param Array aSuffixes
  * @returns Array
  **/
 function mapSuffixes(aPermName, aSuffixes)
 {
@@ -173,8 +192,159 @@ for (let permName in PermissionsTable) {
     AllPossiblePermissions =
       AllPossiblePermissions.concat(mapSuffixes(permName,
                                     PermissionsTable[permName].access));
   }
   else {
     AllPossiblePermissions.push(permName);
   }
 }
+
+/**
+ * Expand an access string into multiple permission names,
+ *   e.g: perm 'contacts' with 'readwrite' =
+ *   ['contacts-read', 'contacts-create', contacts-write']
+ * @param string aPermName
+ * @param string aAccess
+ * @returns Array
+ **/
+function expandPermissions(aPermName, aAccess) {
+  if (!PermissionsTable[aPermName]) {
+    Cu.reportError("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
+    throw new Error("PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName);
+  }
+  if (!aAccess && PermissionsTable[aPermName].access ||
+      aAccess && !PermissionsTable[aPermName].access) {
+    Cu.reportError("PermissionsTable.jsm: expandPermissions: Invalid Manifest");
+    throw new Error("PermissionsTable.jsm: expandPermissions: Invalid Manifest");
+  }
+  if (!PermissionsTable[aPermName].access) {
+    return [aPermName];
+  }
+
+  let requestedSuffixes = [];
+  switch(aAccess) {
+  case READONLY:
+    requestedSuffixes.push("read");
+    break;
+  case CREATEONLY:
+    requestedSuffixes.push("create");
+    break;
+  case READCREATE:
+    requestedSuffixes.push("read", "create");
+    break;
+  case READWRITE:
+    requestedSuffixes.push("read", "create", "write");
+    break;
+  default:
+    return [];
+  }
+
+  let permArr = mapSuffixes(aPermName, requestedSuffixes);
+
+  let expandedPerms = [];
+  for (let idx in permArr) {
+    if (PermissionsTable[aPermName].access.indexOf(requestedSuffixes[idx]) != -1) {
+      expandedPerms.push(permArr[idx]);
+    }
+  }
+  return expandedPerms;
+}
+
+let PermissionsInstaller = {
+/**
+   * Install permissisions or remove deprecated permissions upon re-install
+   * @param object aData
+   *        The just-installed app configuration
+   * @param boolean aIsReinstall
+   *        Indicates the app was just re-installed
+   * @returns void
+   **/
+  installPermissions: function installPermissions(aApp, aIsReinstall, aOnError) {
+    try {
+      let newManifest = new ManifestHelper(aApp.manifest, aApp.origin);
+      if (!newManifest.permissions && !aIsReinstall) {
+        return;
+      }
+
+      if (aIsReinstall) {
+        // Compare the original permissions against the new permissions
+        // Remove any deprecated Permissions
+
+        if (newManifest.permissions) {
+          // Expand perms
+          let newPerms = [];
+          for (let perm in newManifest.permissions) {
+            let _perms = expandPermissions(perm,
+                                           newManifest.permissions[perm].access);
+            newPerms = newPerms.concat(_perms);
+          }
+
+          for (let idx in AllPossiblePermissions) {
+            let index = newPerms.indexOf(AllPossiblePermissions[idx]);
+            if (index == -1) {
+              // See if the permission was installed previously
+              let _perm = PermSettings.get(AllPossiblePermissions[idx],
+                                           aApp.manifestURL,
+                                           aApp.origin,
+                                           false);
+              if (_perm == "unknown" || _perm == "deny") {
+                // All 'deny' permissions should be preserved
+                continue;
+              }
+              // Remove the deprecated permission
+              // TODO: use PermSettings.remove, see bug 793204
+              PermSettings.set(AllPossiblePermissions[idx],
+                               "unknown",
+                               aApp.manifestURL,
+                               aApp.origin,
+                               false);
+            }
+          }
+        }
+      }
+
+      let installPermType;
+      // Check to see if the 'webapp' is app/priv/certified
+      switch (AppsUtils.getAppManifestStatus(newManifest)) {
+      case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
+        installPermType = "certified";
+        break;
+      case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
+        installPermType = "privileged";
+        break;
+      case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
+        installPermType = "app";
+        break;
+      default:
+        // Cannot determine app type, abort install by throwing an error
+        throw new Error("Webapps.jsm: Cannot determine app type, install cancelled");
+      }
+
+      for (let permName in newManifest.permissions) {
+        if (!PermissionsTable[permName]) {
+          throw new Error("Webapps.jsm: '" + permName + "'" +
+                         " is not a valid Webapps permission type. Aborting Webapp installation");
+          return;
+        }
+
+        let perms = expandPermissions(permName,
+                                      newManifest.permissions[permName].access);
+        for (let idx in perms) {
+          let perm = PermissionsTable[permName][installPermType];
+          let permValue = PERM_TO_STRING[perm];
+          PermSettings.set(perms[idx],
+                           permValue,
+                           aApp.manifestURL,
+                           aApp.origin,
+                           false);
+        }
+      }
+    }
+    catch (ex) {
+      debug("Caught webapps install permissions error");
+      Cu.reportError(ex);
+      if (aOnError) {
+        aOnError();
+      }
+    }
+  }
+}
\ No newline at end of file
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -11,47 +11,29 @@ const Cr = Components.results;
 
 let EXPORTED_SYMBOLS = ["DOMApplicationRegistry"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
-Cu.import("resource://gre/modules/PermissionsTable.jsm");
+Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
 
 function debug(aMsg) {
   //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
 }
 
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
-// Permission access flags
-const READONLY = "readonly";
-const CREATEONLY = "createonly";
-const READCREATE = "readcreate";
-const READWRITE = "readwrite";
-
-const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
-
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "PermSettings",
-                                   "@mozilla.org/permissionSettings;1",
-                                   "nsIDOMPermissionSettings");
-
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
-XPCOMUtils.defineLazyServiceGetter(this,
-                                   "permissionManager",
-                                   "@mozilla.org/permissionmanager;1",
-                                   "nsIPermissionManager");
-
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageBroadcaster");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
@@ -66,90 +48,16 @@ XPCOMUtils.defineLazyGetter(this, "msgmg
   const DIRECTORY_NAME = "webappsDir";
 #else
   // If we're executing in the context of the webapp runtime, the data files
   // are in a different directory (currently the Firefox profile that installed
   // the webapp); otherwise, they're in the current profile.
   const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
 #endif
 
-/**
- * Determine the type of app (app, privileged, certified)
- * that is installed by the manifest
- * @param object aManifest
- * @returns integer
- **/
-function getAppManifestStatus(aManifest)
-{
-  let type = aManifest.type || "web";
-
-  switch(type) {
-  case "web":
-    return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
-  case "privileged":
-    return Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
-  case "certified":
-    return Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
-  default:
-    throw new Error("Webapps.jsm: Undetermined app manifest type");
-  }
-}
-
-/**
- * Expand an access string into multiple permission names,
- *   e.g: perm 'contacts' with 'readwrite' =
- *   ['contacts-read', 'contacts-create', contacts-write']
- * @param string aPermName
- * @param string aAccess
- * @returns Array
- **/
-function expandPermissions(aPermName, aAccess)
-{
-  if (!PermissionsTable[aPermName]) {
-    Cu.reportError("Unknown permission: " + aPermName);
-    throw new Error("Webapps.jsm: App install failed, Unknown Permission: " + aPermName);
-  }
-  if (!aAccess && PermissionsTable[aPermName].access ||
-      aAccess && !PermissionsTable[aPermName].access) {
-    Cu.reportError("Webapps.jsm: installPermissions: Invalid Manifest");
-    throw new Error("Webapps.jsm: App install failed, Invalid Manifest");
-  }
-  if (!PermissionsTable[aPermName].access) {
-    return [aPermName];
-  }
-
-  let requestedSuffixes = [];
-  switch(aAccess) {
-  case READONLY:
-    requestedSuffixes.push("read");
-    break;
-  case CREATEONLY:
-    requestedSuffixes.push("create");
-    break;
-  case READCREATE:
-    requestedSuffixes.push("read", "create");
-    break;
-  case READWRITE:
-    requestedSuffixes.push("read", "create", "write");
-    break;
-  default:
-    return [];
-  }
-
-  let permArr = mapSuffixes(aPermName, requestedSuffixes);
-
-  let expandedPerms = [];
-  for (let idx in permArr) {
-    if (PermissionsTable[aPermName].access.indexOf(requestedSuffixes[idx]) != -1) {
-      expandedPerms.push(permArr[idx]);
-    }
-  }
-  return expandedPerms;
-}
-
 let DOMApplicationRegistry = {
   appsFile: null,
   webapps: { },
   children: [ ],
   allAppsLaunchable: false,
   downloads: { },
 
   init: function() {
@@ -794,116 +702,16 @@ let DOMApplicationRegistry = {
                                     : updateService.scheduleUpdate(appcacheURI, docURI, null);
       cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
       if (aOfflineCacheObserver) {
         cacheUpdate.addObserver(aOfflineCacheObserver, false);
       }
     }
   },
 
-  /**
-   * Install permissisions or remove deprecated permissions upon re-install
-   * @param object aAppObject
-   *        The just installed AppUtils cloned appObject
-   * @param object aData
-   *        The just-installed app configuration
-   * @param boolean aIsReinstall
-   *        Indicates the app was just re-installed
-   * @returns void
-   **/
-  installPermissions:
-  function installPermissions(aAppObject, aData, aIsReinstall)
-  {
-    try {
-      let newManifest = new ManifestHelper(aData.app.manifest, aData.app.origin);
-      if (!newManifest.permissions && !aIsReinstall) {
-        return;
-      }
-
-      if (aIsReinstall) {
-        // Compare the original permissions against the new permissions
-        // Remove any deprecated Permissions
-
-        if (newManifest.permissions) {
-          // Expand perms
-          let newPerms = [];
-          for (let perm in newManifest.permissions) {
-            let _perms = expandPermissions(perm,
-                                           newManifest.permissions[perm].access);
-            newPerms = newPerms.concat(_perms);
-          }
-
-          for (let idx in AllPossiblePermissions) {
-            let index = newPerms.indexOf(AllPossiblePermissions[idx]);
-            if (index == -1) {
-              // See if the permission was installed previously
-              let _perm = PermSettings.get(AllPossiblePermissions[idx],
-                                           aData.app.manifestURL,
-                                           aData.app.origin,
-                                           false);
-              if (_perm == "unknown" || _perm == "deny") {
-                // All 'deny' permissions should be preserved
-                continue;
-              }
-              // Remove the deprecated permission
-              // TODO: use PermSettings.remove, see bug 793204
-              PermSettings.set(AllPossiblePermissions[idx],
-                               "unknown",
-                               aData.app.manifestURL,
-                               aData.app.origin,
-                               false);
-            }
-          }
-        }
-      }
-
-      let installPermType;
-      // Check to see if the 'webapp' is app/priv/certified
-      switch (getAppManifestStatus(newManifest)) {
-      case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
-        installPermType = "certified";
-        break;
-      case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
-        installPermType = "privileged";
-        break;
-      case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
-        installPermType = "app";
-        break;
-      default:
-        // Cannot determine app type, abort install by throwing an error
-        throw new Error("Webapps.jsm: Cannot determine app type, install cancelled");
-      }
-
-      for (let permName in newManifest.permissions) {
-        if (!PermissionsTable[permName]) {
-          throw new Error("Webapps.jsm: '" + permName + "'" +
-                         " is not a valid Webapps permission type. Aborting Webapp installation");
-          return;
-        }
-
-        let perms = expandPermissions(permName,
-                                      newManifest.permissions[permName].access);
-        for (let idx in perms) {
-          let perm = PermissionsTable[permName][installPermType];
-          let permValue = PERM_TO_STRING[perm];
-          PermSettings.set(perms[idx],
-                           permValue,
-                           aData.app.manifestURL,
-                           aData.app.origin,
-                           false);
-        }
-      }
-    }
-    catch (ex) {
-      debug("Caught webapps install permissions error");
-      Cu.reportError(ex);
-      this.uninstall(aData);
-    }
-   },
-
   checkForUpdate: function(aData, aMm) {
     let app = this.getAppByManifestURL(aData.manifestURL);
     if (!app) {
       aData.error = "NO_SUCH_APP";
       aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
       return;
     }
 
@@ -1108,17 +916,21 @@ let DOMApplicationRegistry = {
       appObject.downloadAvailable = false;
       appObject.downloading = false;
       appObject.readyToApplyDownload = false;
     }
 
     appObject.name = manifest.name;
 
     this.webapps[id] = appObject;
-    this.installPermissions(appObject, aData, isReinstall);
+
+    PermissionsInstaller.installPermissions(aData.app, isReinstall, (function() {
+      this.uninstall(aData, aData.mm);
+    }).bind(this));
+
     ["installState", "downloadAvailable",
      "downloading", "downloadSize", "readyToApplyDownload"].forEach(function(aProp) {
       aData.app[aProp] = appObject[aProp];
      });
 
     if (!aFromSync)
       this._saveApps((function() {
         this.broadcastMessage("Webapps:Install:Return:OK", aData);
@@ -1264,30 +1076,30 @@ let DOMApplicationRegistry = {
     }
 
     function getInferedStatus() {
       // XXX Update once we have digital signatures (bug 772365)
       return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
     }
 
     function getAppStatus(aManifest) {
-      let manifestStatus = getAppManifestStatus(aManifest);
+      let manifestStatus = AppsUtils.getAppManifestStatus(aManifest);
       let inferedStatus = getInferedStatus();
 
       return (Services.prefs.getBoolPref("dom.mozApps.dev_mode") ? manifestStatus
                                                                 : inferedStatus);
     }
     // Returns true if the privilege level from the manifest
     // is lower or equal to the one we infered for the app.
     function checkAppStatus(aManifest) {
       if (Services.prefs.getBoolPref("dom.mozApps.dev_mode")) {
         return true;
       }
 
-      return (getAppManifestStatus(aManifest) <= getInferedStatus());
+      return (AppsUtils.getAppManifestStatus(aManifest) <= getInferedStatus());
     }
 
     debug("About to download " + aManifest.fullPackagePath());
 
     let requestChannel = NetUtil.newChannel(aManifest.fullPackagePath())
                                 .QueryInterface(Ci.nsIHttpChannel);
     this.downloads[aApp.manifestURL] =
       { channel:requestChannel,