diff options
Diffstat (limited to 'dom/apps/PermissionsInstaller.jsm')
-rw-r--r-- | dom/apps/PermissionsInstaller.jsm | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/dom/apps/PermissionsInstaller.jsm b/dom/apps/PermissionsInstaller.jsm new file mode 100644 index 000000000..e3ed3aca8 --- /dev/null +++ b/dom/apps/PermissionsInstaller.jsm @@ -0,0 +1,210 @@ +/* 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; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/AppsUtils.jsm"); +Cu.import("resource://gre/modules/PermissionSettings.jsm"); +Cu.import("resource://gre/modules/PermissionsTable.jsm"); + +this.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"]; + +function debug(aMsg) { + //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n"); +} + +this.PermissionsInstaller = { + /** + * Install permissisions or remove deprecated permissions upon re-install. + * @param object aApp + * The just-installed app configuration. + * The properties used are manifestURL, origin and manifest. + * @param boolean aIsReinstall + * Indicates the app was just re-installed + * @param function aOnError + * A function called if an error occurs + * @returns void + **/ + installPermissions: function installPermissions(aApp, aIsReinstall, + aOnError) { + try { + let newManifest = + new ManifestHelper(aApp.manifest, aApp.origin, aApp.manifestURL); + if (!newManifest.permissions && !aIsReinstall) { + return; + } + + if (aIsReinstall) { + // Compare the original permissions against the new permissions + // Remove any deprecated Permissions + + if (newManifest.permissions) { + // Expand permission names. + let newPermNames = []; + for (let permName in newManifest.permissions) { + let expandedPermNames = + expandPermissions(permName, + newManifest.permissions[permName].access); + newPermNames = newPermNames.concat(expandedPermNames); + } + + newPermNames.push("indexedDB"); + + // Add the appcache related permissions. + if (newManifest.appcache_path) { + newPermNames = newPermNames.concat(["offline-app", "pin-app"]); + } + + for (let idx in AllPossiblePermissions) { + let permName = AllPossiblePermissions[idx]; + let index = newPermNames.indexOf(permName); + if (index == -1) { + // See if the permission was installed previously. + let permValue = + PermissionSettingsModule.getPermission(permName, + aApp.manifestURL, + aApp.origin, + false); + if (permValue == "unknown" || permValue == "deny") { + // All 'deny' permissions should be preserved + continue; + } + // Remove the deprecated permission + PermissionSettingsModule.removePermission(permName, + aApp.manifestURL, + aApp.origin, + false); + } + } + } + } + + // Check to see if the 'webapp' is app/privileged/certified. + let appStatus; + switch (AppsUtils.getAppManifestStatus(aApp.manifest)) { + case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: + appStatus = "certified"; + break; + case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED: + appStatus = "privileged"; + break; + case Ci.nsIPrincipal.APP_STATUS_INSTALLED: + appStatus = "app"; + break; + default: + // Cannot determine app type, abort install by throwing an error. + throw new Error("PermissionsInstaller.jsm: " + + "Cannot determine the app's status. Install cancelled."); + break; + } + + this._setPermission("indexedDB", "allow", aApp); + + // Add the appcache related permissions. We allow it for all kinds of + // apps. + if (newManifest.appcache_path) { + this._setPermission("offline-app", "allow", aApp); + this._setPermission("pin-app", "allow", aApp); + } + + for (let permName in newManifest.permissions) { + if (!PermissionsTable[permName]) { + Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" + + " is not a valid Webapps permission name."); + dump("PermissionsInstaller.jsm: '" + permName + "'" + + " is not a valid Webapps permission name."); + continue; + } + + let expandedPermNames = + expandPermissions(permName, + newManifest.permissions[permName].access); + for (let idx in expandedPermNames) { + + let isPromptPermission = + PermissionsTable[permName][appStatus] === PROMPT_ACTION; + + // We silently upgrade the permission to whatever the permission + // is for certified apps (ALLOW or PROMPT) only if the + // following holds true: + // * The app is preinstalled + // * The permission that would be granted is PROMPT + // * The app is privileged + let permission = + aApp.isPreinstalled && isPromptPermission && + appStatus === "privileged" + ? PermissionsTable[permName]["certified"] + : PermissionsTable[permName][appStatus]; + + let permValue = PERM_TO_STRING[permission]; + if (isPromptPermission) { + // If the permission is prompt, keep the current value. This will + // work even on a system update, with the caveat that if a + // ALLOW/DENY permission is changed to PROMPT then the system should + // inform the user that he can now change a permission that he could + // not change before. + permValue = + PermissionSettingsModule.getPermission(expandedPermNames[idx], + aApp.manifestURL, + aApp.origin, + false, + aApp.isCachedPackage); + if (permValue === "unknown") { + permValue = PERM_TO_STRING[permission]; + } + } + + this._setPermission(expandedPermNames[idx], permValue, aApp); + } + } + } + catch (ex) { + dump("Caught webapps install permissions error for " + aApp.origin + + " : " + ex + "\n"); + Cu.reportError(ex); + if (aOnError) { + aOnError(); + } + } + }, + + /** + * Set a permission value. + * @param string aPermName + * The permission name. + * @param string aPermValue + * The permission value. + * @param object aApp + * The just-installed app configuration. + * The properties used are manifestURL, origin, appId, isCachedPackage. + * @returns void + **/ + _setPermission: function setPermission(aPermName, aPermValue, aApp) { + PermissionSettingsModule.addPermission({ + type: aPermName, + origin: aApp.origin, + manifestURL: aApp.manifestURL, + value: aPermValue, + browserFlag: false, + localId: aApp.localId, + isCachedPackage: aApp.isCachedPackage, + }); + } +}; |