michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/AppsUtils.jsm"); michael@0: Cu.import("resource://gre/modules/PermissionSettings.jsm"); michael@0: Cu.import("resource://gre/modules/PermissionsTable.jsm"); michael@0: michael@0: this.EXPORTED_SYMBOLS = ["PermissionsInstaller"]; michael@0: const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION; michael@0: const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION; michael@0: const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION; michael@0: const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION; michael@0: michael@0: // Permission access flags michael@0: const READONLY = "readonly"; michael@0: const CREATEONLY = "createonly"; michael@0: const READCREATE = "readcreate"; michael@0: const READWRITE = "readwrite"; michael@0: michael@0: const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"]; michael@0: michael@0: function debug(aMsg) { michael@0: //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n"); michael@0: } michael@0: michael@0: // An array carring all the possible (expanded) permission names. michael@0: let AllPossiblePermissions = []; michael@0: for (let permName in PermissionsTable) { michael@0: let expandedPermNames = []; michael@0: if (PermissionsTable[permName].access) { michael@0: expandedPermNames = expandPermissions(permName, READWRITE); michael@0: } else { michael@0: expandedPermNames = expandPermissions(permName); michael@0: } michael@0: AllPossiblePermissions = AllPossiblePermissions.concat(expandedPermNames); michael@0: AllPossiblePermissions = michael@0: AllPossiblePermissions.concat(["offline-app", "pin-app"]); michael@0: } michael@0: michael@0: this.PermissionsInstaller = { michael@0: /** michael@0: * Install permissisions or remove deprecated permissions upon re-install. michael@0: * @param object aApp michael@0: * The just-installed app configuration. michael@0: * The properties used are manifestURL, origin and manifest. michael@0: * @param boolean aIsReinstall michael@0: * Indicates the app was just re-installed michael@0: * @param function aOnError michael@0: * A function called if an error occurs michael@0: * @returns void michael@0: **/ michael@0: installPermissions: function installPermissions(aApp, aIsReinstall, aOnError) { michael@0: try { michael@0: let newManifest = new ManifestHelper(aApp.manifest, aApp.origin); michael@0: if (!newManifest.permissions && !aIsReinstall) { michael@0: return; michael@0: } michael@0: michael@0: if (aIsReinstall) { michael@0: // Compare the original permissions against the new permissions michael@0: // Remove any deprecated Permissions michael@0: michael@0: if (newManifest.permissions) { michael@0: // Expand permission names. michael@0: let newPermNames = []; michael@0: for (let permName in newManifest.permissions) { michael@0: let expandedPermNames = michael@0: expandPermissions(permName, michael@0: newManifest.permissions[permName].access); michael@0: newPermNames = newPermNames.concat(expandedPermNames); michael@0: } michael@0: michael@0: // Add the appcache related permissions. michael@0: if (newManifest.appcache_path) { michael@0: newPermNames = newPermNames.concat(["offline-app", "pin-app"]); michael@0: } michael@0: michael@0: for (let idx in AllPossiblePermissions) { michael@0: let permName = AllPossiblePermissions[idx]; michael@0: let index = newPermNames.indexOf(permName); michael@0: if (index == -1) { michael@0: // See if the permission was installed previously. michael@0: let permValue = michael@0: PermissionSettingsModule.getPermission(permName, michael@0: aApp.manifestURL, michael@0: aApp.origin, michael@0: false); michael@0: if (permValue == "unknown" || permValue == "deny") { michael@0: // All 'deny' permissions should be preserved michael@0: continue; michael@0: } michael@0: // Remove the deprecated permission michael@0: PermissionSettingsModule.removePermission(permName, michael@0: aApp.manifestURL, michael@0: aApp.origin, michael@0: false); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Check to see if the 'webapp' is app/privileged/certified. michael@0: let appStatus; michael@0: switch (AppsUtils.getAppManifestStatus(aApp.manifest)) { michael@0: case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: michael@0: appStatus = "certified"; michael@0: break; michael@0: case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED: michael@0: appStatus = "privileged"; michael@0: break; michael@0: case Ci.nsIPrincipal.APP_STATUS_INSTALLED: michael@0: appStatus = "app"; michael@0: break; michael@0: default: michael@0: // Cannot determine app type, abort install by throwing an error. michael@0: throw new Error("PermissionsInstaller.jsm: " + michael@0: "Cannot determine the app's status. Install cancelled."); michael@0: break; michael@0: } michael@0: michael@0: // Add the appcache related permissions. We allow it for all kinds of michael@0: // apps. michael@0: if (newManifest.appcache_path) { michael@0: this._setPermission("offline-app", "allow", aApp); michael@0: this._setPermission("pin-app", "allow", aApp); michael@0: } michael@0: michael@0: for (let permName in newManifest.permissions) { michael@0: if (!PermissionsTable[permName]) { michael@0: Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" + michael@0: " is not a valid Webapps permission name."); michael@0: dump("PermissionsInstaller.jsm: '" + permName + "'" + michael@0: " is not a valid Webapps permission name."); michael@0: continue; michael@0: } michael@0: michael@0: let expandedPermNames = michael@0: expandPermissions(permName, michael@0: newManifest.permissions[permName].access); michael@0: for (let idx in expandedPermNames) { michael@0: this._setPermission(expandedPermNames[idx], michael@0: PERM_TO_STRING[PermissionsTable[permName][appStatus]], michael@0: aApp); michael@0: } michael@0: } michael@0: } michael@0: catch (ex) { michael@0: dump("Caught webapps install permissions error for " + aApp.origin); michael@0: Cu.reportError(ex); michael@0: if (aOnError) { michael@0: aOnError(); michael@0: } michael@0: } michael@0: }, michael@0: michael@0: /** michael@0: * Set a permission value. michael@0: * @param string aPermName michael@0: * The permission name. michael@0: * @param string aPermValue michael@0: * The permission value. michael@0: * @param object aApp michael@0: * The just-installed app configuration. michael@0: * The properties used are manifestURL and origin. michael@0: * @returns void michael@0: **/ michael@0: _setPermission: function setPermission(aPermName, aPermValue, aApp) { michael@0: PermissionSettingsModule.addPermission({ michael@0: type: aPermName, michael@0: origin: aApp.origin, michael@0: manifestURL: aApp.manifestURL, michael@0: value: aPermValue, michael@0: browserFlag: false michael@0: }); michael@0: } michael@0: };