1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const Ci = Components.interfaces;
8 const Cu = Components.utils;
10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
11 Cu.import("resource://gre/modules/AppsUtils.jsm");
12 Cu.import("resource://gre/modules/PermissionSettings.jsm");
13 Cu.import("resource://gre/modules/PermissionsTable.jsm");
15 this.EXPORTED_SYMBOLS = ["PermissionsInstaller"];
16 const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
17 const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
18 const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
19 const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
21 // Permission access flags
22 const READONLY = "readonly";
23 const CREATEONLY = "createonly";
24 const READCREATE = "readcreate";
25 const READWRITE = "readwrite";
27 const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
29 function debug(aMsg) {
30 //dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
33 this.PermissionsInstaller = {
35 * Install permissisions or remove deprecated permissions upon re-install.
37 * The just-installed app configuration.
38 * The properties used are manifestURL, origin and manifest.
39 * @param boolean aIsReinstall
40 * Indicates the app was just re-installed
41 * @param function aOnError
42 * A function called if an error occurs
45 installPermissions: function installPermissions(aApp, aIsReinstall,
49 new ManifestHelper(aApp.manifest, aApp.origin, aApp.manifestURL);
50 if (!newManifest.permissions && !aIsReinstall) {
55 // Compare the original permissions against the new permissions
56 // Remove any deprecated Permissions
58 if (newManifest.permissions) {
59 // Expand permission names.
60 let newPermNames = [];
61 for (let permName in newManifest.permissions) {
62 let expandedPermNames =
63 expandPermissions(permName,
64 newManifest.permissions[permName].access);
65 newPermNames = newPermNames.concat(expandedPermNames);
68 newPermNames.push("indexedDB");
70 // Add the appcache related permissions.
71 if (newManifest.appcache_path) {
72 newPermNames = newPermNames.concat(["offline-app", "pin-app"]);
75 for (let idx in AllPossiblePermissions) {
76 let permName = AllPossiblePermissions[idx];
77 let index = newPermNames.indexOf(permName);
79 // See if the permission was installed previously.
81 PermissionSettingsModule.getPermission(permName,
85 if (permValue == "unknown" || permValue == "deny") {
86 // All 'deny' permissions should be preserved
89 // Remove the deprecated permission
90 PermissionSettingsModule.removePermission(permName,
99 // Check to see if the 'webapp' is app/privileged/certified.
101 switch (AppsUtils.getAppManifestStatus(aApp.manifest)) {
102 case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
103 appStatus = "certified";
105 case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
106 appStatus = "privileged";
108 case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
110 if (aApp.kind == "hosted-trusted") {
111 appStatus = "trusted";
115 // Cannot determine app type, abort install by throwing an error.
116 throw new Error("PermissionsInstaller.jsm: " +
117 "Cannot determine the app's status. Install cancelled.");
121 this._setPermission("indexedDB", "allow", aApp);
123 // Add the appcache related permissions. We allow it for all kinds of
125 if (newManifest.appcache_path) {
126 this._setPermission("offline-app", "allow", aApp);
127 this._setPermission("pin-app", "allow", aApp);
130 for (let permName in newManifest.permissions) {
131 if (!PermissionsTable[permName]) {
132 Cu.reportError("PermissionsInstaller.jsm: '" + permName + "'" +
133 " is not a valid Webapps permission name.");
134 dump("PermissionsInstaller.jsm: '" + permName + "'" +
135 " is not a valid Webapps permission name.");
139 let expandedPermNames =
140 expandPermissions(permName,
141 newManifest.permissions[permName].access);
142 for (let idx in expandedPermNames) {
144 let isPromptPermission =
145 PermissionsTable[permName][appStatus] === PROMPT_ACTION;
147 // We silently upgrade the permission to whatever the permission
148 // is for certified apps (ALLOW or PROMPT) only if the
149 // following holds true:
150 // * The app is preinstalled
151 // * The permission that would be granted is PROMPT
152 // * The app is privileged
154 aApp.isPreinstalled && isPromptPermission &&
155 appStatus === "privileged"
156 ? PermissionsTable[permName]["certified"]
157 : PermissionsTable[permName][appStatus];
159 let permValue = PERM_TO_STRING[permission];
160 if (isPromptPermission) {
161 // If the permission is prompt, keep the current value. This will
162 // work even on a system update, with the caveat that if a
163 // ALLOW/DENY permission is changed to PROMPT then the system should
164 // inform the user that he can now change a permission that he could
165 // not change before.
167 PermissionSettingsModule.getPermission(expandedPermNames[idx],
171 if (permValue === "unknown") {
172 permValue = PERM_TO_STRING[permission];
176 this._setPermission(expandedPermNames[idx], permValue, aApp);
181 dump("Caught webapps install permissions error for " + aApp.origin);
190 * Set a permission value.
191 * @param string aPermName
192 * The permission name.
193 * @param string aPermValue
194 * The permission value.
196 * The just-installed app configuration.
197 * The properties used are manifestURL and origin.
200 _setPermission: function setPermission(aPermName, aPermValue, aApp) {
201 PermissionSettingsModule.addPermission({
204 manifestURL: aApp.manifestURL,