Bumping manifests a=b2g-bump
[gecko.git] / dom / apps / PermissionsInstaller.jsm
blob35844a5bd579a339e6c861c8093a1ddfafef99f9
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/. */
5 "use strict";
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 = {
34   /**
35    * Install permissisions or remove deprecated permissions upon re-install.
36    * @param object aApp
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
43    * @returns void
44    **/
45   installPermissions: function installPermissions(aApp, aIsReinstall,
46                                                   aOnError) {
47     try {
48       let newManifest =
49         new ManifestHelper(aApp.manifest, aApp.origin, aApp.manifestURL);
50       if (!newManifest.permissions && !aIsReinstall) {
51         return;
52       }
54       if (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);
66           }
68           newPermNames.push("indexedDB");
70           // Add the appcache related permissions.
71           if (newManifest.appcache_path) {
72             newPermNames = newPermNames.concat(["offline-app", "pin-app"]);
73           }
75           for (let idx in AllPossiblePermissions) {
76             let permName = AllPossiblePermissions[idx];
77             let index = newPermNames.indexOf(permName);
78             if (index == -1) {
79               // See if the permission was installed previously.
80               let permValue =
81                 PermissionSettingsModule.getPermission(permName,
82                                                        aApp.manifestURL,
83                                                        aApp.origin,
84                                                        false);
85               if (permValue == "unknown" || permValue == "deny") {
86                 // All 'deny' permissions should be preserved
87                 continue;
88               }
89               // Remove the deprecated permission
90               PermissionSettingsModule.removePermission(permName,
91                                                         aApp.manifestURL,
92                                                         aApp.origin,
93                                                         false);
94             }
95           }
96         }
97       }
99       // Check to see if the 'webapp' is app/privileged/certified.
100       let appStatus;
101       switch (AppsUtils.getAppManifestStatus(aApp.manifest)) {
102       case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
103         appStatus = "certified";
104         break;
105       case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
106         appStatus = "privileged";
107         break;
108       case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
109         appStatus = "app";
110         if (aApp.kind == "hosted-trusted") {
111           appStatus = "trusted";
112         }
113         break;
114       default:
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.");
118         break;
119       }
121       this._setPermission("indexedDB", "allow", aApp);
123       // Add the appcache related permissions. We allow it for all kinds of
124       // apps.
125       if (newManifest.appcache_path) {
126         this._setPermission("offline-app", "allow", aApp);
127         this._setPermission("pin-app", "allow", aApp);
128       }
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.");
136           continue;
137         }
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
153           let permission =
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.
166             permValue =
167               PermissionSettingsModule.getPermission(expandedPermNames[idx],
168                                                      aApp.manifestURL,
169                                                      aApp.origin,
170                                                      false);
171             if (permValue === "unknown") {
172               permValue = PERM_TO_STRING[permission];
173             }
174           }
176           this._setPermission(expandedPermNames[idx], permValue, aApp);
177         }
178       }
179     }
180     catch (ex) {
181       dump("Caught webapps install permissions error for " + aApp.origin);
182       Cu.reportError(ex);
183       if (aOnError) {
184         aOnError();
185       }
186     }
187   },
189   /**
190    * Set a permission value.
191    * @param string aPermName
192    *        The permission name.
193    * @param string aPermValue
194    *        The permission value.
195    * @param object aApp
196    *        The just-installed app configuration.
197    *        The properties used are manifestURL and origin.
198    * @returns void
199    **/
200   _setPermission: function setPermission(aPermName, aPermValue, aApp) {
201     PermissionSettingsModule.addPermission({
202       type: aPermName,
203       origin: aApp.origin,
204       manifestURL: aApp.manifestURL,
205       value: aPermValue,
206       browserFlag: false
207     });
208   }