1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/apps/src/PermissionsTable.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,486 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const Ci = Components.interfaces; 1.11 +const Cu = Components.utils; 1.12 + 1.13 +this.EXPORTED_SYMBOLS = [ 1.14 + "PermissionsTable", 1.15 + "PermissionsReverseTable", 1.16 + "expandPermissions", 1.17 + "appendAccessToPermName", 1.18 + "isExplicitInPermissionsTable" 1.19 +]; 1.20 + 1.21 +// Permission access flags 1.22 +const READONLY = "readonly"; 1.23 +const CREATEONLY = "createonly"; 1.24 +const READCREATE = "readcreate"; 1.25 +const READWRITE = "readwrite"; 1.26 + 1.27 +const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION; 1.28 +const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION; 1.29 +const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION; 1.30 +const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION; 1.31 + 1.32 +// Permissions Matrix: https://docs.google.com/spreadsheet/ccc?key=0Akyz_Bqjgf5pdENVekxYRjBTX0dCXzItMnRyUU1RQ0E#gid=0 1.33 + 1.34 +// Permissions that are implicit: 1.35 +// battery-status, network-information, vibration, 1.36 +// device-capabilities 1.37 + 1.38 +this.PermissionsTable = { geolocation: { 1.39 + app: PROMPT_ACTION, 1.40 + privileged: PROMPT_ACTION, 1.41 + certified: PROMPT_ACTION 1.42 + }, 1.43 + camera: { 1.44 + app: DENY_ACTION, 1.45 + privileged: PROMPT_ACTION, 1.46 + certified: ALLOW_ACTION 1.47 + }, 1.48 + alarms: { 1.49 + app: ALLOW_ACTION, 1.50 + privileged: ALLOW_ACTION, 1.51 + certified: ALLOW_ACTION 1.52 + }, 1.53 + "tcp-socket": { 1.54 + app: DENY_ACTION, 1.55 + privileged: ALLOW_ACTION, 1.56 + certified: ALLOW_ACTION 1.57 + }, 1.58 + "network-events": { 1.59 + app: DENY_ACTION, 1.60 + privileged: DENY_ACTION, 1.61 + certified: ALLOW_ACTION 1.62 + }, 1.63 + contacts: { 1.64 + app: DENY_ACTION, 1.65 + privileged: PROMPT_ACTION, 1.66 + certified: ALLOW_ACTION, 1.67 + access: ["read", "write", "create"] 1.68 + }, 1.69 + "device-storage:apps": { 1.70 + app: DENY_ACTION, 1.71 + privileged: DENY_ACTION, 1.72 + certified: ALLOW_ACTION, 1.73 + access: ["read"] 1.74 + }, 1.75 + "device-storage:crashes": { 1.76 + app: DENY_ACTION, 1.77 + privileged: DENY_ACTION, 1.78 + certified: ALLOW_ACTION, 1.79 + access: ["read"] 1.80 + }, 1.81 + "device-storage:pictures": { 1.82 + app: DENY_ACTION, 1.83 + privileged: PROMPT_ACTION, 1.84 + certified: ALLOW_ACTION, 1.85 + access: ["read", "write", "create"] 1.86 + }, 1.87 + "device-storage:videos": { 1.88 + app: DENY_ACTION, 1.89 + privileged: PROMPT_ACTION, 1.90 + certified: ALLOW_ACTION, 1.91 + access: ["read", "write", "create"] 1.92 + }, 1.93 + "device-storage:music": { 1.94 + app: DENY_ACTION, 1.95 + privileged: PROMPT_ACTION, 1.96 + certified: ALLOW_ACTION, 1.97 + access: ["read", "write", "create"] 1.98 + }, 1.99 + "device-storage:sdcard": { 1.100 + app: DENY_ACTION, 1.101 + privileged: PROMPT_ACTION, 1.102 + certified: ALLOW_ACTION, 1.103 + access: ["read", "write", "create"] 1.104 + }, 1.105 + sms: { 1.106 + app: DENY_ACTION, 1.107 + privileged: DENY_ACTION, 1.108 + certified: ALLOW_ACTION 1.109 + }, 1.110 + telephony: { 1.111 + app: DENY_ACTION, 1.112 + privileged: DENY_ACTION, 1.113 + certified: ALLOW_ACTION 1.114 + }, 1.115 + browser: { 1.116 + app: DENY_ACTION, 1.117 + privileged: ALLOW_ACTION, 1.118 + certified: ALLOW_ACTION 1.119 + }, 1.120 + bluetooth: { 1.121 + app: DENY_ACTION, 1.122 + privileged: DENY_ACTION, 1.123 + certified: ALLOW_ACTION 1.124 + }, 1.125 + mobileconnection: { 1.126 + app: DENY_ACTION, 1.127 + privileged: DENY_ACTION, 1.128 + certified: ALLOW_ACTION 1.129 + }, 1.130 + mobilenetwork: { 1.131 + app: DENY_ACTION, 1.132 + privileged: ALLOW_ACTION, 1.133 + certified: ALLOW_ACTION 1.134 + }, 1.135 + power: { 1.136 + app: DENY_ACTION, 1.137 + privileged: DENY_ACTION, 1.138 + certified: ALLOW_ACTION 1.139 + }, 1.140 + push: { 1.141 + app: ALLOW_ACTION, 1.142 + privileged: ALLOW_ACTION, 1.143 + certified: ALLOW_ACTION 1.144 + }, 1.145 + settings: { 1.146 + app: DENY_ACTION, 1.147 + privileged: DENY_ACTION, 1.148 + certified: ALLOW_ACTION, 1.149 + access: ["read", "write"], 1.150 + additional: ["indexedDB-chrome-settings"] 1.151 + }, 1.152 + permissions: { 1.153 + app: DENY_ACTION, 1.154 + privileged: DENY_ACTION, 1.155 + certified: ALLOW_ACTION 1.156 + }, 1.157 + phonenumberservice: { 1.158 + app: DENY_ACTION, 1.159 + privileged: DENY_ACTION, 1.160 + certified: ALLOW_ACTION 1.161 + }, 1.162 + fmradio: { 1.163 + app: DENY_ACTION, 1.164 + privileged: ALLOW_ACTION, 1.165 + certified: ALLOW_ACTION 1.166 + }, 1.167 + attention: { 1.168 + app: DENY_ACTION, 1.169 + privileged: DENY_ACTION, 1.170 + certified: ALLOW_ACTION 1.171 + }, 1.172 + "webapps-manage": { 1.173 + app: DENY_ACTION, 1.174 + privileged: DENY_ACTION, 1.175 + certified: ALLOW_ACTION 1.176 + }, 1.177 + "backgroundservice": { 1.178 + app: DENY_ACTION, 1.179 + privileged: DENY_ACTION, 1.180 + certified: ALLOW_ACTION 1.181 + }, 1.182 + "desktop-notification": { 1.183 + app: ALLOW_ACTION, 1.184 + privileged: ALLOW_ACTION, 1.185 + certified: ALLOW_ACTION 1.186 + }, 1.187 + "networkstats-manage": { 1.188 + app: DENY_ACTION, 1.189 + privileged: DENY_ACTION, 1.190 + certified: ALLOW_ACTION 1.191 + }, 1.192 + "wifi-manage": { 1.193 + app: DENY_ACTION, 1.194 + privileged: DENY_ACTION, 1.195 + certified: ALLOW_ACTION 1.196 + }, 1.197 + "systemXHR": { 1.198 + app: DENY_ACTION, 1.199 + privileged: ALLOW_ACTION, 1.200 + certified: ALLOW_ACTION 1.201 + }, 1.202 + "voicemail": { 1.203 + app: DENY_ACTION, 1.204 + privileged: DENY_ACTION, 1.205 + certified: ALLOW_ACTION 1.206 + }, 1.207 + "deprecated-hwvideo": { 1.208 + app: DENY_ACTION, 1.209 + privileged: DENY_ACTION, 1.210 + certified: ALLOW_ACTION 1.211 + }, 1.212 + "idle": { 1.213 + app: DENY_ACTION, 1.214 + privileged: DENY_ACTION, 1.215 + certified: ALLOW_ACTION 1.216 + }, 1.217 + "time": { 1.218 + app: DENY_ACTION, 1.219 + privileged: DENY_ACTION, 1.220 + certified: ALLOW_ACTION 1.221 + }, 1.222 + "embed-apps": { 1.223 + app: DENY_ACTION, 1.224 + privileged: DENY_ACTION, 1.225 + certified: ALLOW_ACTION 1.226 + }, 1.227 + "storage": { 1.228 + app: ALLOW_ACTION, 1.229 + privileged: ALLOW_ACTION, 1.230 + certified: ALLOW_ACTION, 1.231 + substitute: [ 1.232 + "indexedDB-unlimited", 1.233 + "default-persistent-storage" 1.234 + ] 1.235 + }, 1.236 + "background-sensors": { 1.237 + app: DENY_ACTION, 1.238 + privileged: DENY_ACTION, 1.239 + certified: ALLOW_ACTION 1.240 + }, 1.241 + cellbroadcast: { 1.242 + app: DENY_ACTION, 1.243 + privileged: DENY_ACTION, 1.244 + certified: ALLOW_ACTION 1.245 + }, 1.246 + "audio-channel-normal": { 1.247 + app: ALLOW_ACTION, 1.248 + privileged: ALLOW_ACTION, 1.249 + certified: ALLOW_ACTION 1.250 + }, 1.251 + "audio-channel-content": { 1.252 + app: ALLOW_ACTION, 1.253 + privileged: ALLOW_ACTION, 1.254 + certified: ALLOW_ACTION 1.255 + }, 1.256 + "audio-channel-notification": { 1.257 + app: DENY_ACTION, 1.258 + privileged: ALLOW_ACTION, 1.259 + certified: ALLOW_ACTION 1.260 + }, 1.261 + "audio-channel-alarm": { 1.262 + app: DENY_ACTION, 1.263 + privileged: ALLOW_ACTION, 1.264 + certified: ALLOW_ACTION 1.265 + }, 1.266 + "audio-channel-telephony": { 1.267 + app: DENY_ACTION, 1.268 + privileged: DENY_ACTION, 1.269 + certified: ALLOW_ACTION 1.270 + }, 1.271 + "audio-channel-ringer": { 1.272 + app: DENY_ACTION, 1.273 + privileged: DENY_ACTION, 1.274 + certified: ALLOW_ACTION 1.275 + }, 1.276 + "audio-channel-publicnotification": { 1.277 + app: DENY_ACTION, 1.278 + privileged: DENY_ACTION, 1.279 + certified: ALLOW_ACTION 1.280 + }, 1.281 + "open-remote-window": { 1.282 + app: DENY_ACTION, 1.283 + privileged: DENY_ACTION, 1.284 + certified: ALLOW_ACTION 1.285 + }, 1.286 + "input": { 1.287 + app: DENY_ACTION, 1.288 + privileged: ALLOW_ACTION, 1.289 + certified: ALLOW_ACTION 1.290 + }, 1.291 + "input-manage": { 1.292 + app: DENY_ACTION, 1.293 + privileged: DENY_ACTION, 1.294 + certified: ALLOW_ACTION 1.295 + }, 1.296 + "wappush": { 1.297 + app: DENY_ACTION, 1.298 + privileged: DENY_ACTION, 1.299 + certified: ALLOW_ACTION 1.300 + }, 1.301 + "audio-capture": { 1.302 + app: PROMPT_ACTION, 1.303 + privileged: PROMPT_ACTION, 1.304 + certified: PROMPT_ACTION 1.305 + }, 1.306 + "nfc": { 1.307 + app: DENY_ACTION, 1.308 + privileged: DENY_ACTION, 1.309 + certified: ALLOW_ACTION, 1.310 + access: ["read", "write"] 1.311 + }, 1.312 + "nfc-manager": { 1.313 + app: DENY_ACTION, 1.314 + privileged: DENY_ACTION, 1.315 + certified: ALLOW_ACTION 1.316 + }, 1.317 + "speaker-control": { 1.318 + app: DENY_ACTION, 1.319 + privileged: ALLOW_ACTION, 1.320 + certified: ALLOW_ACTION 1.321 + }, 1.322 + "downloads": { 1.323 + app: DENY_ACTION, 1.324 + privileged: DENY_ACTION, 1.325 + certified: ALLOW_ACTION 1.326 + }, 1.327 + "video-capture": { 1.328 + app: PROMPT_ACTION, 1.329 + privileged: PROMPT_ACTION, 1.330 + certified: PROMPT_ACTION 1.331 + }, 1.332 + }; 1.333 + 1.334 +/** 1.335 + * Append access modes to the permission name as suffixes. 1.336 + * e.g. permission name 'contacts' with ['read', 'write'] = 1.337 + * ['contacts-read', contacts-write'] 1.338 + * @param string aPermName 1.339 + * @param array aAccess 1.340 + * @returns array containing access-appended permission names. 1.341 + **/ 1.342 +this.appendAccessToPermName = function appendAccessToPermName(aPermName, aAccess) { 1.343 + if (aAccess.length == 0) { 1.344 + return [aPermName]; 1.345 + } 1.346 + return aAccess.map(function(aMode) { 1.347 + return aPermName + "-" + aMode; 1.348 + }); 1.349 +}; 1.350 + 1.351 +/** 1.352 + * Expand an access string into multiple permission names, 1.353 + * e.g: permission name 'contacts' with 'readwrite' = 1.354 + * ['contacts-read', 'contacts-create', 'contacts-write'] 1.355 + * @param string aPermName 1.356 + * @param string aAccess (optional) 1.357 + * @returns array containing expanded permission names. 1.358 + **/ 1.359 +this.expandPermissions = function expandPermissions(aPermName, aAccess) { 1.360 + if (!PermissionsTable[aPermName]) { 1.361 + let errorMsg = 1.362 + "PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName; 1.363 + Cu.reportError(errorMsg); 1.364 + dump(errorMsg); 1.365 + return []; 1.366 + } 1.367 + 1.368 + const tableEntry = PermissionsTable[aPermName]; 1.369 + 1.370 + if (tableEntry.substitute && tableEntry.additional) { 1.371 + let errorMsg = 1.372 + "PermissionsTable.jsm: expandPermissions: Can't handle both 'substitute' " + 1.373 + "and 'additional' entries for permission: " + aPermName; 1.374 + Cu.reportError(errorMsg); 1.375 + dump(errorMsg); 1.376 + return []; 1.377 + } 1.378 + 1.379 + if (!aAccess && tableEntry.access || 1.380 + aAccess && !tableEntry.access) { 1.381 + let errorMsg = 1.382 + "PermissionsTable.jsm: expandPermissions: Invalid access for permission " + 1.383 + aPermName + ": " + aAccess + "\n"; 1.384 + Cu.reportError(errorMsg); 1.385 + dump(errorMsg); 1.386 + return []; 1.387 + } 1.388 + 1.389 + let expandedPermNames = []; 1.390 + 1.391 + if (tableEntry.access && aAccess) { 1.392 + let requestedSuffixes = []; 1.393 + switch (aAccess) { 1.394 + case READONLY: 1.395 + requestedSuffixes.push("read"); 1.396 + break; 1.397 + case CREATEONLY: 1.398 + requestedSuffixes.push("create"); 1.399 + break; 1.400 + case READCREATE: 1.401 + requestedSuffixes.push("read", "create"); 1.402 + break; 1.403 + case READWRITE: 1.404 + requestedSuffixes.push("read", "create", "write"); 1.405 + break; 1.406 + default: 1.407 + return []; 1.408 + } 1.409 + 1.410 + let permArr = appendAccessToPermName(aPermName, requestedSuffixes); 1.411 + 1.412 + // Add the same suffix to each of the additions. 1.413 + if (tableEntry.additional) { 1.414 + for each (let additional in tableEntry.additional) { 1.415 + permArr = permArr.concat(appendAccessToPermName(additional, requestedSuffixes)); 1.416 + } 1.417 + } 1.418 + 1.419 + // Only add the suffixed version if the suffix exists in the table. 1.420 + for (let idx in permArr) { 1.421 + let suffix = requestedSuffixes[idx % requestedSuffixes.length]; 1.422 + if (tableEntry.access.indexOf(suffix) != -1) { 1.423 + expandedPermNames.push(permArr[idx]); 1.424 + } 1.425 + } 1.426 + } else if (tableEntry.substitute) { 1.427 + expandedPermNames = expandedPermNames.concat(tableEntry.substitute); 1.428 + } else { 1.429 + expandedPermNames.push(aPermName); 1.430 + // Include each of the additions exactly as they appear in the table. 1.431 + if (tableEntry.additional) { 1.432 + expandedPermNames = expandedPermNames.concat(tableEntry.additional); 1.433 + } 1.434 + } 1.435 + 1.436 + return expandedPermNames; 1.437 +}; 1.438 + 1.439 +this.PermissionsReverseTable = (function () { 1.440 + // PermissionsTable as it is works well for direct searches, but not 1.441 + // so well for reverse ones (that is, if I get something like 1.442 + // device-storage:music-read or indexedDB-chrome-settings-read how 1.443 + // do I know which permission it really is? Hence this table is 1.444 + // born. The idea is that 1.445 + // reverseTable[device-storage:music-read] should return 1.446 + // device-storage:music 1.447 + let reverseTable = {}; 1.448 + 1.449 + for (let permName in PermissionsTable) { 1.450 + let permAliases; 1.451 + if (PermissionsTable[permName].access) { 1.452 + permAliases = expandPermissions(permName, "readwrite"); 1.453 + } else { 1.454 + permAliases = expandPermissions(permName); 1.455 + } 1.456 + for (let i = 0; i < permAliases.length; i++) { 1.457 + reverseTable[permAliases[i]] = permName; 1.458 + } 1.459 + } 1.460 + 1.461 + return reverseTable; 1.462 + 1.463 +})(); 1.464 + 1.465 +this.isExplicitInPermissionsTable = function(aPermName, aIntStatus) { 1.466 + 1.467 + // Check to see if the 'webapp' is app/privileged/certified. 1.468 + let appStatus; 1.469 + switch (aIntStatus) { 1.470 + case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: 1.471 + appStatus = "certified"; 1.472 + break; 1.473 + case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED: 1.474 + appStatus = "privileged"; 1.475 + break; 1.476 + default: // If it isn't certified or privileged, it's app 1.477 + appStatus = "app"; 1.478 + break; 1.479 + } 1.480 + 1.481 + let realPerm = PermissionsReverseTable[aPermName]; 1.482 + 1.483 + if (realPerm) { 1.484 + return (PermissionsTable[realPerm][appStatus] == 1.485 + Ci.nsIPermissionManager.PROMPT_ACTION); 1.486 + } else { 1.487 + return false; 1.488 + } 1.489 +}