|
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/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 function debug(s) { |
|
8 //dump("-*- PermissionSettings Module: " + s + "\n"); |
|
9 } |
|
10 |
|
11 const Cu = Components.utils; |
|
12 const Cc = Components.classes; |
|
13 const Ci = Components.interfaces; |
|
14 |
|
15 this.EXPORTED_SYMBOLS = ["PermissionSettingsModule"]; |
|
16 |
|
17 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
|
18 Cu.import("resource://gre/modules/Services.jsm"); |
|
19 Cu.import("resource://gre/modules/PermissionsTable.jsm"); |
|
20 |
|
21 XPCOMUtils.defineLazyServiceGetter(this, "ppmm", |
|
22 "@mozilla.org/parentprocessmessagemanager;1", |
|
23 "nsIMessageListenerManager"); |
|
24 |
|
25 XPCOMUtils.defineLazyServiceGetter(this, |
|
26 "permissionManager", |
|
27 "@mozilla.org/permissionmanager;1", |
|
28 "nsIPermissionManager"); |
|
29 |
|
30 XPCOMUtils.defineLazyServiceGetter(this, |
|
31 "secMan", |
|
32 "@mozilla.org/scriptsecuritymanager;1", |
|
33 "nsIScriptSecurityManager"); |
|
34 |
|
35 XPCOMUtils.defineLazyServiceGetter(this, |
|
36 "appsService", |
|
37 "@mozilla.org/AppsService;1", |
|
38 "nsIAppsService"); |
|
39 |
|
40 this.PermissionSettingsModule = { |
|
41 init: function init() { |
|
42 debug("Init"); |
|
43 ppmm.addMessageListener("PermissionSettings:AddPermission", this); |
|
44 Services.obs.addObserver(this, "profile-before-change", false); |
|
45 }, |
|
46 |
|
47 |
|
48 _isChangeAllowed: function(aPrincipal, aPermName, aAction) { |
|
49 // Bug 812289: |
|
50 // Change is allowed from a child process when all of the following |
|
51 // conditions stand true: |
|
52 // * the action isn't "unknown" (so the change isn't a delete) if the app |
|
53 // is installed |
|
54 // * the permission already exists on the database |
|
55 // * the permission is marked as explicit on the permissions table |
|
56 // Note that we *have* to check the first two conditions here because |
|
57 // permissionManager doesn't know if it's being called as a result of |
|
58 // a parent process or child process request. We could check |
|
59 // if the permission is actually explicit (and thus modifiable) or not |
|
60 // on permissionManager also but we currently don't. |
|
61 let perm = |
|
62 permissionManager.testExactPermissionFromPrincipal(aPrincipal,aPermName); |
|
63 let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus); |
|
64 |
|
65 return (aAction === "unknown" && |
|
66 aPrincipal.appStatus === Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) || |
|
67 (aAction !== "unknown" && |
|
68 (perm !== Ci.nsIPermissionManager.UNKNOWN_ACTION) && |
|
69 isExplicit); |
|
70 }, |
|
71 |
|
72 addPermission: function addPermission(aData, aCallbacks) { |
|
73 |
|
74 this._internalAddPermission(aData, true, aCallbacks); |
|
75 |
|
76 }, |
|
77 |
|
78 |
|
79 _internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) { |
|
80 let uri = Services.io.newURI(aData.origin, null, null); |
|
81 let appID = appsService.getAppLocalIdByManifestURL(aData.manifestURL); |
|
82 let principal = secMan.getAppCodebasePrincipal(uri, appID, aData.browserFlag); |
|
83 |
|
84 let action; |
|
85 switch (aData.value) |
|
86 { |
|
87 case "unknown": |
|
88 action = Ci.nsIPermissionManager.UNKNOWN_ACTION; |
|
89 break; |
|
90 case "allow": |
|
91 action = Ci.nsIPermissionManager.ALLOW_ACTION; |
|
92 break; |
|
93 case "deny": |
|
94 action = Ci.nsIPermissionManager.DENY_ACTION; |
|
95 break; |
|
96 case "prompt": |
|
97 action = Ci.nsIPermissionManager.PROMPT_ACTION; |
|
98 break; |
|
99 default: |
|
100 dump("Unsupported PermisionSettings Action: " + aData.value +"\n"); |
|
101 action = Ci.nsIPermissionManager.UNKNOWN_ACTION; |
|
102 } |
|
103 |
|
104 if (aAllowAllChanges || |
|
105 this._isChangeAllowed(principal, aData.type, aData.value)) { |
|
106 debug("add: " + aData.origin + " " + appID + " " + action); |
|
107 permissionManager.addFromPrincipal(principal, aData.type, action); |
|
108 return true; |
|
109 } else { |
|
110 debug("add Failure: " + aData.origin + " " + appID + " " + action); |
|
111 return false; // This isn't currently used, see comment on setPermission |
|
112 } |
|
113 }, |
|
114 |
|
115 getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) { |
|
116 debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin); |
|
117 let uri = Services.io.newURI(aOrigin, null, null); |
|
118 let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); |
|
119 let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag); |
|
120 let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermName); |
|
121 |
|
122 switch (result) |
|
123 { |
|
124 case Ci.nsIPermissionManager.UNKNOWN_ACTION: |
|
125 return "unknown"; |
|
126 case Ci.nsIPermissionManager.ALLOW_ACTION: |
|
127 return "allow"; |
|
128 case Ci.nsIPermissionManager.DENY_ACTION: |
|
129 return "deny"; |
|
130 case Ci.nsIPermissionManager.PROMPT_ACTION: |
|
131 return "prompt"; |
|
132 default: |
|
133 dump("Unsupported PermissionSettings Action!\n"); |
|
134 return "unknown"; |
|
135 } |
|
136 }, |
|
137 |
|
138 removePermission: function removePermission(aPermName, aManifestURL, aOrigin, aBrowserFlag) { |
|
139 let data = { |
|
140 type: aPermName, |
|
141 origin: aOrigin, |
|
142 manifestURL: aManifestURL, |
|
143 value: "unknown", |
|
144 browserFlag: aBrowserFlag |
|
145 }; |
|
146 this._internalAddPermission(data, true); |
|
147 }, |
|
148 |
|
149 observe: function observe(aSubject, aTopic, aData) { |
|
150 ppmm.removeMessageListener("PermissionSettings:AddPermission", this); |
|
151 Services.obs.removeObserver(this, "profile-before-change"); |
|
152 ppmm = null; |
|
153 }, |
|
154 |
|
155 receiveMessage: function receiveMessage(aMessage) { |
|
156 debug("PermissionSettings::receiveMessage " + aMessage.name); |
|
157 let mm = aMessage.target; |
|
158 let msg = aMessage.data; |
|
159 |
|
160 let result; |
|
161 switch (aMessage.name) { |
|
162 case "PermissionSettings:AddPermission": |
|
163 let success = false; |
|
164 let errorMsg = |
|
165 " from a content process with no 'permissions' privileges."; |
|
166 if (mm.assertPermission("permissions")) { |
|
167 success = this._internalAddPermission(msg, false); |
|
168 if (!success) { |
|
169 // Just kill the calling process |
|
170 mm.assertPermission("permissions-modify-implicit"); |
|
171 errorMsg = " had an implicit permission change. Child process killed."; |
|
172 } |
|
173 } |
|
174 |
|
175 if (!success) { |
|
176 Cu.reportError("PermissionSettings message " + msg.type + errorMsg); |
|
177 return null; |
|
178 } |
|
179 break; |
|
180 } |
|
181 } |
|
182 } |
|
183 |
|
184 PermissionSettingsModule.init(); |