dom/messages/SystemMessagePermissionsChecker.jsm

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 const Ci = Components.interfaces;
michael@0 8 const Cu = Components.utils;
michael@0 9
michael@0 10 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 11 Cu.import("resource://gre/modules/Services.jsm");
michael@0 12 Cu.import("resource://gre/modules/AppsUtils.jsm");
michael@0 13 Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
michael@0 14 Cu.import("resource://gre/modules/PermissionsTable.jsm");
michael@0 15 Cu.import("resource://gre/modules/PermissionSettings.jsm");
michael@0 16
michael@0 17 this.EXPORTED_SYMBOLS = ["SystemMessagePermissionsChecker",
michael@0 18 "SystemMessagePermissionsTable"];
michael@0 19
michael@0 20 function debug(aStr) {
michael@0 21 // dump("SystemMessagePermissionsChecker.jsm: " + aStr + "\n");
michael@0 22 }
michael@0 23
michael@0 24 // This table maps system message to permission(s), indicating only
michael@0 25 // the system messages granted by the page's permissions are allowed
michael@0 26 // to be registered or sent to that page. Note the empty permission
michael@0 27 // set means this type of system message is always permitted.
michael@0 28
michael@0 29 this.SystemMessagePermissionsTable = {
michael@0 30 "activity": { },
michael@0 31 "alarm": {
michael@0 32 "alarms": []
michael@0 33 },
michael@0 34 "bluetooth-dialer-command": {
michael@0 35 "telephony": []
michael@0 36 },
michael@0 37 "bluetooth-cancel": {
michael@0 38 "bluetooth": []
michael@0 39 },
michael@0 40 "bluetooth-hid-status-changed": {
michael@0 41 "bluetooth": []
michael@0 42 },
michael@0 43 "bluetooth-pairing-request": {
michael@0 44 "bluetooth": []
michael@0 45 },
michael@0 46 "bluetooth-opp-transfer-complete": {
michael@0 47 "bluetooth": []
michael@0 48 },
michael@0 49 "bluetooth-opp-update-progress": {
michael@0 50 "bluetooth": []
michael@0 51 },
michael@0 52 "bluetooth-opp-receiving-file-confirmation": {
michael@0 53 "bluetooth": []
michael@0 54 },
michael@0 55 "bluetooth-opp-transfer-start": {
michael@0 56 "bluetooth": []
michael@0 57 },
michael@0 58 "connection": { },
michael@0 59 "dummy-system-message": { }, // for system message testing framework
michael@0 60 "headset-button": { },
michael@0 61 "icc-stkcommand": {
michael@0 62 "settings": ["read", "write"]
michael@0 63 },
michael@0 64 "media-button": { },
michael@0 65 "networkstats-alarm": {
michael@0 66 "networkstats-manage": []
michael@0 67 },
michael@0 68 "notification": {
michael@0 69 "desktop-notification": []
michael@0 70 },
michael@0 71 "push": {
michael@0 72 "push": []
michael@0 73 },
michael@0 74 "push-register": {
michael@0 75 "push": []
michael@0 76 },
michael@0 77 "sms-delivery-success": {
michael@0 78 "sms": []
michael@0 79 },
michael@0 80 "sms-read-success": {
michael@0 81 "sms": []
michael@0 82 },
michael@0 83 "sms-received": {
michael@0 84 "sms": []
michael@0 85 },
michael@0 86 "sms-sent": {
michael@0 87 "sms": []
michael@0 88 },
michael@0 89 "telephony-new-call": {
michael@0 90 "telephony": []
michael@0 91 },
michael@0 92 "telephony-call-ended": {
michael@0 93 "telephony": []
michael@0 94 },
michael@0 95 "ussd-received": {
michael@0 96 "mobileconnection": []
michael@0 97 },
michael@0 98 "wappush-received": {
michael@0 99 "wappush": []
michael@0 100 },
michael@0 101 "cdma-info-rec-received": {
michael@0 102 "mobileconnection": []
michael@0 103 },
michael@0 104 "nfc-manager-tech-discovered": {
michael@0 105 "nfc-manager": []
michael@0 106 },
michael@0 107 "nfc-manager-tech-lost": {
michael@0 108 "nfc-manager": []
michael@0 109 },
michael@0 110 "nfc-manager-send-file": {
michael@0 111 "nfc-manager": []
michael@0 112 },
michael@0 113 "nfc-powerlevel-change": {
michael@0 114 "settings": ["read", "write"]
michael@0 115 },
michael@0 116 "wifip2p-pairing-request": { },
michael@0 117 "first-run-with-sim": {
michael@0 118 "settings": ["read", "write"]
michael@0 119 }
michael@0 120 };
michael@0 121
michael@0 122 this.SystemMessagePermissionsChecker = {
michael@0 123 /**
michael@0 124 * Return all the needed permission names for the given system message.
michael@0 125 * @param string aSysMsgName
michael@0 126 * The system messsage name.
michael@0 127 * @returns object
michael@0 128 * Format: { permName (string): permNamesWithAccess (string array), ... }
michael@0 129 * Ex, { "settings": ["settings-read", "settings-write"], ... }.
michael@0 130 * Note: an empty object will be returned if it's always permitted.
michael@0 131 * @returns null
michael@0 132 * Return and report error when any unexpected error is ecountered.
michael@0 133 * Ex, when the system message we want to search is not included.
michael@0 134 **/
michael@0 135 getSystemMessagePermissions: function getSystemMessagePermissions(aSysMsgName) {
michael@0 136 debug("getSystemMessagePermissions(): aSysMsgName: " + aSysMsgName);
michael@0 137
michael@0 138 let permNames = SystemMessagePermissionsTable[aSysMsgName];
michael@0 139 if (permNames === undefined) {
michael@0 140 debug("'" + aSysMsgName + "' is not associated with permissions. " +
michael@0 141 "Please add them to the SystemMessagePermissionsTable.");
michael@0 142 return null;
michael@0 143 }
michael@0 144
michael@0 145 let object = { };
michael@0 146 for (let permName in permNames) {
michael@0 147 if (PermissionsTable[permName] === undefined) {
michael@0 148 debug("'" + permName + "' for '" + aSysMsgName + "' is invalid. " +
michael@0 149 "Please correct it in the SystemMessagePermissionsTable.");
michael@0 150 return null;
michael@0 151 }
michael@0 152
michael@0 153 // Construct a new permission name array by adding the access suffixes.
michael@0 154 let access = permNames[permName];
michael@0 155 if (!access || !Array.isArray(access)) {
michael@0 156 debug("'" + permName + "' is not associated with access array. " +
michael@0 157 "Please correct it in the SystemMessagePermissionsTable.");
michael@0 158 return null;
michael@0 159 }
michael@0 160 object[permName] = appendAccessToPermName(permName, access);
michael@0 161 }
michael@0 162 return object
michael@0 163 },
michael@0 164
michael@0 165 /**
michael@0 166 * Check if the system message is permitted to be registered for the given
michael@0 167 * app at start-up based on the permissions claimed in the app's manifest.
michael@0 168 * @param string aSysMsgName
michael@0 169 * The system messsage name.
michael@0 170 * @param string aOrigin
michael@0 171 * The app's origin.
michael@0 172 * @param object aManifest
michael@0 173 * The app's manifest.
michael@0 174 * @returns bool
michael@0 175 * Is permitted or not.
michael@0 176 **/
michael@0 177 isSystemMessagePermittedToRegister:
michael@0 178 function isSystemMessagePermittedToRegister(aSysMsgName, aOrigin, aManifest) {
michael@0 179 debug("isSystemMessagePermittedToRegister(): " +
michael@0 180 "aSysMsgName: " + aSysMsgName + ", " +
michael@0 181 "aOrigin: " + aOrigin + ", " +
michael@0 182 "aManifest: " + JSON.stringify(aManifest));
michael@0 183
michael@0 184 let permNames = this.getSystemMessagePermissions(aSysMsgName);
michael@0 185 if (permNames === null) {
michael@0 186 return false;
michael@0 187 }
michael@0 188
michael@0 189 // Check to see if the 'webapp' is app/privileged/certified.
michael@0 190 let appStatus;
michael@0 191 switch (AppsUtils.getAppManifestStatus(aManifest)) {
michael@0 192 case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
michael@0 193 appStatus = "certified";
michael@0 194 break;
michael@0 195 case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
michael@0 196 appStatus = "privileged";
michael@0 197 break;
michael@0 198 case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
michael@0 199 appStatus = "app";
michael@0 200 break;
michael@0 201 default:
michael@0 202 throw new Error("SystemMessagePermissionsChecker.jsm: " +
michael@0 203 "Cannot decide the app's status. Install cancelled.");
michael@0 204 break;
michael@0 205 }
michael@0 206
michael@0 207 let newManifest = new ManifestHelper(aManifest, aOrigin);
michael@0 208
michael@0 209 for (let permName in permNames) {
michael@0 210 // The app doesn't claim valid permissions for this sytem message.
michael@0 211 if (!newManifest.permissions || !newManifest.permissions[permName]) {
michael@0 212 debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
michael@0 213 "Please add the permission for app: '" + aOrigin + "'.");
michael@0 214 return false;
michael@0 215 }
michael@0 216 let permValue = PermissionsTable[permName][appStatus];
michael@0 217 if (permValue != Ci.nsIPermissionManager.PROMPT_ACTION &&
michael@0 218 permValue != Ci.nsIPermissionManager.ALLOW_ACTION) {
michael@0 219 debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
michael@0 220 "Please add the permission for app: '" + aOrigin + "'.");
michael@0 221 return false;
michael@0 222 }
michael@0 223
michael@0 224 // Compare the expanded permission names between the ones in
michael@0 225 // app's manifest and the ones needed for system message.
michael@0 226 let expandedPermNames =
michael@0 227 expandPermissions(permName,
michael@0 228 newManifest.permissions[permName].access);
michael@0 229
michael@0 230 let permNamesWithAccess = permNames[permName];
michael@0 231
michael@0 232 // Early return false as soon as any permission is not matched.
michael@0 233 for (let idx in permNamesWithAccess) {
michael@0 234 let index = expandedPermNames.indexOf(permNamesWithAccess[idx]);
michael@0 235 if (index == -1) {
michael@0 236 debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
michael@0 237 "Please add the permission for app: '" + aOrigin + "'.");
michael@0 238 return false;
michael@0 239 }
michael@0 240 }
michael@0 241 }
michael@0 242
michael@0 243 // All the permissions needed for this system message are matched.
michael@0 244 return true;
michael@0 245 },
michael@0 246
michael@0 247 /**
michael@0 248 * Check if the system message is permitted to be sent to the given
michael@0 249 * app's page at run-time based on the current app's permissions.
michael@0 250 * @param string aSysMsgName
michael@0 251 * The system messsage name.
michael@0 252 * @param string aPageURL
michael@0 253 * The app's page URL.
michael@0 254 * @param string aManifestURL
michael@0 255 * The app's manifest URL.
michael@0 256 * @returns bool
michael@0 257 * Is permitted or not.
michael@0 258 **/
michael@0 259 isSystemMessagePermittedToSend:
michael@0 260 function isSystemMessagePermittedToSend(aSysMsgName, aPageURL, aManifestURL) {
michael@0 261 debug("isSystemMessagePermittedToSend(): " +
michael@0 262 "aSysMsgName: " + aSysMsgName + ", " +
michael@0 263 "aPageURL: " + aPageURL + ", " +
michael@0 264 "aManifestURL: " + aManifestURL);
michael@0 265
michael@0 266 let permNames = this.getSystemMessagePermissions(aSysMsgName);
michael@0 267 if (permNames === null) {
michael@0 268 return false;
michael@0 269 }
michael@0 270
michael@0 271 let pageURI = Services.io.newURI(aPageURL, null, null);
michael@0 272 for (let permName in permNames) {
michael@0 273 let permNamesWithAccess = permNames[permName];
michael@0 274
michael@0 275 // Early return false as soon as any permission is not matched.
michael@0 276 for (let idx in permNamesWithAccess) {
michael@0 277 if(PermissionSettingsModule.getPermission(permNamesWithAccess[idx],
michael@0 278 aManifestURL,
michael@0 279 pageURI.prePath,
michael@0 280 false) != "allow") {
michael@0 281 debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
michael@0 282 "Please add the permission for app: '" + pageURI.prePath + "'.");
michael@0 283 return false;
michael@0 284 }
michael@0 285 }
michael@0 286 }
michael@0 287
michael@0 288 // All the permissions needed for this system message are matched.
michael@0 289 return true;
michael@0 290 }
michael@0 291 };

mercurial