diff options
Diffstat (limited to 'dom/apps/PermissionsTable.jsm')
-rw-r--r-- | dom/apps/PermissionsTable.jsm | 593 |
1 files changed, 593 insertions, 0 deletions
diff --git a/dom/apps/PermissionsTable.jsm b/dom/apps/PermissionsTable.jsm new file mode 100644 index 000000000..7c6a8490f --- /dev/null +++ b/dom/apps/PermissionsTable.jsm @@ -0,0 +1,593 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const Ci = Components.interfaces; +const Cu = Components.utils; + +this.EXPORTED_SYMBOLS = [ + "PermissionsTable", + "PermissionsReverseTable", + "expandPermissions", + "appendAccessToPermName", + "isExplicitInPermissionsTable", + "AllPossiblePermissions" +]; + +// Permission access flags +const READONLY = "readonly"; +const CREATEONLY = "createonly"; +const READCREATE = "readcreate"; +const READWRITE = "readwrite"; + +const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION; +const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION; +const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION; +const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION; + +// Permissions Matrix: https://docs.google.com/spreadsheet/ccc?key=0Akyz_Bqjgf5pdENVekxYRjBTX0dCXzItMnRyUU1RQ0E#gid=0 + +// Permissions that are implicit: +// battery-status, network-information, vibration, +// device-capabilities + +this.PermissionsTable = { geolocation: { + app: PROMPT_ACTION, + privileged: PROMPT_ACTION, + certified: PROMPT_ACTION + }, + "geolocation-noprompt": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION, + substitute: ["geolocation"] + }, + camera: { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION + }, + alarms: { + app: ALLOW_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "tcp-socket": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "udp-socket": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "network-events": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + contacts: { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + "device-storage:apps": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION, + access: ["read"] + }, + "device-storage:crashes": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION, + access: ["read"] + }, + "device-storage:pictures": { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + "device-storage:videos": { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + "device-storage:music": { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + "device-storage:sdcard": { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + sms: { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "speech-recognition": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + browser: { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "browser:universalxss": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "browser:embedded-system-app": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + mobilenetwork: { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + power: { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + push: { + app: ALLOW_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + settings: { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write"], + additional: ["indexedDB-chrome-settings", "settings-api"] + }, + // This exists purely for tests, no app + // should ever use it. It can only be + // handed out by SpecialPowers. + "settings-clear": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: DENY_ACTION, + additional: ["indexedDB-chrome-settings", "settings-api"] + }, + permissions: { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + attention: { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "global-clickthrough-overlay": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "moz-attention": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION, + substitute: ["attention"] + }, + "webapps-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "homescreen-webapps-manage": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "backgroundservice": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "desktop-notification": { + app: ALLOW_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "networkstats-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "wifi-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "systemXHR": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "idle": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "time": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "embed-apps": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "background-sensors": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-normal": { + app: ALLOW_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-content": { + app: ALLOW_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-notification": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-alarm": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-system": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-channel-telephony": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "moz-audio-channel-telephony": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION, + substitute: ["audio-channel-telephony"] + }, + "audio-channel-ringer": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "moz-audio-channel-ringer": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION, + substitute: ["audio-channel-ringer"] + }, + "audio-channel-publicnotification": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "open-remote-window": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "input": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "input-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "audio-capture": { + app: PROMPT_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION + }, + "audio-capture:3gpp": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "audio-capture:3gpp2": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "speaker-control": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "downloads": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "video-capture": { + app: PROMPT_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION + }, + "feature-detection": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + // This permission doesn't actually grant access to + // anything. It exists only to check the correctness + // of web prompt composed permissions in tests. + "test-permission": { + app: PROMPT_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write", "create"] + }, + "firefox-accounts": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "moz-firefox-accounts": { + app: DENY_ACTION, + privileged: PROMPT_ACTION, + certified: ALLOW_ACTION, + substitute: ["firefox-accounts"] + }, + "themeable": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "settings:wallpaper.image": { + app: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION, + access: ["read", "write"], + additional: ["settings-api"] + }, + "tv": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "before-after-keyboard-event": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "presentation-device-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "secureelement-manage": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "inputport": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "system-update": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "open-hidden-window": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "moz-extremely-unstable-and-will-change-webcomponents": { + app: DENY_ACTION, + trusted: DENY_ACTION, + privileged: ALLOW_ACTION, + certified: ALLOW_ACTION + }, + "system-app-only-audio-channels-in-app": { + app: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + }, + "previously-certified-app": { + app: DENY_ACTION, + trusted: DENY_ACTION, + privileged: DENY_ACTION, + certified: ALLOW_ACTION + } + }; + +/** + * Append access modes to the permission name as suffixes. + * e.g. permission name 'contacts' with ['read', 'write'] = + * ['contacts-read', contacts-write'] + * @param string aPermName + * @param array aAccess + * @returns array containing access-appended permission names. + **/ +this.appendAccessToPermName = function appendAccessToPermName(aPermName, aAccess) { + if (aAccess.length == 0) { + return [aPermName]; + } + return aAccess.map(function(aMode) { + return aPermName + "-" + aMode; + }); +}; + +/** + * Expand an access string into multiple permission names, + * e.g: permission name 'contacts' with 'readwrite' = + * ['contacts-read', 'contacts-create', 'contacts-write'] + * @param string aPermName + * @param string aAccess (optional) + * @returns array containing expanded permission names. + **/ +this.expandPermissions = function expandPermissions(aPermName, aAccess) { + if (!PermissionsTable[aPermName]) { + let errorMsg = + "PermissionsTable.jsm: expandPermissions: Unknown Permission: " + aPermName; + Cu.reportError(errorMsg); + dump(errorMsg); + return []; + } + + const tableEntry = PermissionsTable[aPermName]; + + if (tableEntry.substitute && tableEntry.additional) { + let errorMsg = + "PermissionsTable.jsm: expandPermissions: Can't handle both 'substitute' " + + "and 'additional' entries for permission: " + aPermName; + Cu.reportError(errorMsg); + dump(errorMsg); + return []; + } + + if (!aAccess && tableEntry.access || + aAccess && !tableEntry.access) { + let errorMsg = + "PermissionsTable.jsm: expandPermissions: Invalid access for permission " + + aPermName + ": " + aAccess + "\n"; + Cu.reportError(errorMsg); + dump(errorMsg); + return []; + } + + let expandedPermNames = []; + + if (tableEntry.access && aAccess) { + let requestedSuffixes = []; + switch (aAccess) { + case READONLY: + requestedSuffixes.push("read"); + break; + case CREATEONLY: + requestedSuffixes.push("create"); + break; + case READCREATE: + requestedSuffixes.push("read", "create"); + break; + case READWRITE: + requestedSuffixes.push("read", "create", "write"); + break; + default: + return []; + } + + let permArr = appendAccessToPermName(aPermName, requestedSuffixes); + + // Add the same suffix to each of the additions. + if (tableEntry.additional) { + for (let additional of tableEntry.additional) { + permArr = permArr.concat(appendAccessToPermName(additional, requestedSuffixes)); + } + } + + // Only add the suffixed version if the suffix exists in the table. + for (let idx in permArr) { + let suffix = requestedSuffixes[idx % requestedSuffixes.length]; + if (tableEntry.access.indexOf(suffix) != -1) { + expandedPermNames.push(permArr[idx]); + } + } + } else if (tableEntry.substitute) { + expandedPermNames = expandedPermNames.concat(tableEntry.substitute); + } else { + expandedPermNames.push(aPermName); + // Include each of the additions exactly as they appear in the table. + if (tableEntry.additional) { + expandedPermNames = expandedPermNames.concat(tableEntry.additional); + } + } + + return expandedPermNames; +}; + +this.PermissionsReverseTable = {}; +this.AllPossiblePermissions = []; + +(function () { + // PermissionsTable as it is works well for direct searches, but not + // so well for reverse ones (that is, if I get something like + // device-storage:music-read or indexedDB-chrome-settings-read how + // do I know which permission it really is? Hence this table is + // born. The idea is that + // reverseTable[device-storage:music-read] should return + // device-storage:music + // + // We also need a list of all the possible permissions for things like the + // settingsmanager, so construct that while we're at it. + for (let permName in PermissionsTable) { + let permAliases = []; + if (PermissionsTable[permName].access) { + permAliases = expandPermissions(permName, "readwrite"); + } else if (!PermissionsTable[permName].substitute) { + permAliases = expandPermissions(permName); + } + for (let i = 0; i < permAliases.length; i++) { + PermissionsReverseTable[permAliases[i]] = permName; + AllPossiblePermissions.push(permAliases[i]); + } + } + AllPossiblePermissions = + AllPossiblePermissions.concat(["indexedDB", "offline-app", "pin-app"]); +})(); + +this.isExplicitInPermissionsTable = function(aPermName, aIntStatus) { + + // Check to see if the 'webapp' is app/privileged/certified. + let appStatus; + switch (aIntStatus) { + case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: + appStatus = "certified"; + break; + case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED: + appStatus = "privileged"; + break; + default: // If it isn't certified or privileged, it's app + appStatus = "app"; + break; + } + + let realPerm = PermissionsReverseTable[aPermName]; + + if (realPerm) { + return (PermissionsTable[realPerm][appStatus] == + Ci.nsIPermissionManager.PROMPT_ACTION); + } else { + return false; + } +} |