mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 13:58:49 +00:00
7b6e3a2d4a
This removes a lot of the plumbing for having the platform embed itself through IPC which was required for B2G running the browser as both shell and browser application.
589 lines
24 KiB
JavaScript
589 lines
24 KiB
JavaScript
/* 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
|
|
},
|
|
"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;
|
|
}
|
|
}
|