1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/messages/SystemMessagePermissionsChecker.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,291 @@ 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 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.14 +Cu.import("resource://gre/modules/Services.jsm"); 1.15 +Cu.import("resource://gre/modules/AppsUtils.jsm"); 1.16 +Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); 1.17 +Cu.import("resource://gre/modules/PermissionsTable.jsm"); 1.18 +Cu.import("resource://gre/modules/PermissionSettings.jsm"); 1.19 + 1.20 +this.EXPORTED_SYMBOLS = ["SystemMessagePermissionsChecker", 1.21 + "SystemMessagePermissionsTable"]; 1.22 + 1.23 +function debug(aStr) { 1.24 + // dump("SystemMessagePermissionsChecker.jsm: " + aStr + "\n"); 1.25 +} 1.26 + 1.27 +// This table maps system message to permission(s), indicating only 1.28 +// the system messages granted by the page's permissions are allowed 1.29 +// to be registered or sent to that page. Note the empty permission 1.30 +// set means this type of system message is always permitted. 1.31 + 1.32 +this.SystemMessagePermissionsTable = { 1.33 + "activity": { }, 1.34 + "alarm": { 1.35 + "alarms": [] 1.36 + }, 1.37 + "bluetooth-dialer-command": { 1.38 + "telephony": [] 1.39 + }, 1.40 + "bluetooth-cancel": { 1.41 + "bluetooth": [] 1.42 + }, 1.43 + "bluetooth-hid-status-changed": { 1.44 + "bluetooth": [] 1.45 + }, 1.46 + "bluetooth-pairing-request": { 1.47 + "bluetooth": [] 1.48 + }, 1.49 + "bluetooth-opp-transfer-complete": { 1.50 + "bluetooth": [] 1.51 + }, 1.52 + "bluetooth-opp-update-progress": { 1.53 + "bluetooth": [] 1.54 + }, 1.55 + "bluetooth-opp-receiving-file-confirmation": { 1.56 + "bluetooth": [] 1.57 + }, 1.58 + "bluetooth-opp-transfer-start": { 1.59 + "bluetooth": [] 1.60 + }, 1.61 + "connection": { }, 1.62 + "dummy-system-message": { }, // for system message testing framework 1.63 + "headset-button": { }, 1.64 + "icc-stkcommand": { 1.65 + "settings": ["read", "write"] 1.66 + }, 1.67 + "media-button": { }, 1.68 + "networkstats-alarm": { 1.69 + "networkstats-manage": [] 1.70 + }, 1.71 + "notification": { 1.72 + "desktop-notification": [] 1.73 + }, 1.74 + "push": { 1.75 + "push": [] 1.76 + }, 1.77 + "push-register": { 1.78 + "push": [] 1.79 + }, 1.80 + "sms-delivery-success": { 1.81 + "sms": [] 1.82 + }, 1.83 + "sms-read-success": { 1.84 + "sms": [] 1.85 + }, 1.86 + "sms-received": { 1.87 + "sms": [] 1.88 + }, 1.89 + "sms-sent": { 1.90 + "sms": [] 1.91 + }, 1.92 + "telephony-new-call": { 1.93 + "telephony": [] 1.94 + }, 1.95 + "telephony-call-ended": { 1.96 + "telephony": [] 1.97 + }, 1.98 + "ussd-received": { 1.99 + "mobileconnection": [] 1.100 + }, 1.101 + "wappush-received": { 1.102 + "wappush": [] 1.103 + }, 1.104 + "cdma-info-rec-received": { 1.105 + "mobileconnection": [] 1.106 + }, 1.107 + "nfc-manager-tech-discovered": { 1.108 + "nfc-manager": [] 1.109 + }, 1.110 + "nfc-manager-tech-lost": { 1.111 + "nfc-manager": [] 1.112 + }, 1.113 + "nfc-manager-send-file": { 1.114 + "nfc-manager": [] 1.115 + }, 1.116 + "nfc-powerlevel-change": { 1.117 + "settings": ["read", "write"] 1.118 + }, 1.119 + "wifip2p-pairing-request": { }, 1.120 + "first-run-with-sim": { 1.121 + "settings": ["read", "write"] 1.122 + } 1.123 +}; 1.124 + 1.125 +this.SystemMessagePermissionsChecker = { 1.126 + /** 1.127 + * Return all the needed permission names for the given system message. 1.128 + * @param string aSysMsgName 1.129 + * The system messsage name. 1.130 + * @returns object 1.131 + * Format: { permName (string): permNamesWithAccess (string array), ... } 1.132 + * Ex, { "settings": ["settings-read", "settings-write"], ... }. 1.133 + * Note: an empty object will be returned if it's always permitted. 1.134 + * @returns null 1.135 + * Return and report error when any unexpected error is ecountered. 1.136 + * Ex, when the system message we want to search is not included. 1.137 + **/ 1.138 + getSystemMessagePermissions: function getSystemMessagePermissions(aSysMsgName) { 1.139 + debug("getSystemMessagePermissions(): aSysMsgName: " + aSysMsgName); 1.140 + 1.141 + let permNames = SystemMessagePermissionsTable[aSysMsgName]; 1.142 + if (permNames === undefined) { 1.143 + debug("'" + aSysMsgName + "' is not associated with permissions. " + 1.144 + "Please add them to the SystemMessagePermissionsTable."); 1.145 + return null; 1.146 + } 1.147 + 1.148 + let object = { }; 1.149 + for (let permName in permNames) { 1.150 + if (PermissionsTable[permName] === undefined) { 1.151 + debug("'" + permName + "' for '" + aSysMsgName + "' is invalid. " + 1.152 + "Please correct it in the SystemMessagePermissionsTable."); 1.153 + return null; 1.154 + } 1.155 + 1.156 + // Construct a new permission name array by adding the access suffixes. 1.157 + let access = permNames[permName]; 1.158 + if (!access || !Array.isArray(access)) { 1.159 + debug("'" + permName + "' is not associated with access array. " + 1.160 + "Please correct it in the SystemMessagePermissionsTable."); 1.161 + return null; 1.162 + } 1.163 + object[permName] = appendAccessToPermName(permName, access); 1.164 + } 1.165 + return object 1.166 + }, 1.167 + 1.168 + /** 1.169 + * Check if the system message is permitted to be registered for the given 1.170 + * app at start-up based on the permissions claimed in the app's manifest. 1.171 + * @param string aSysMsgName 1.172 + * The system messsage name. 1.173 + * @param string aOrigin 1.174 + * The app's origin. 1.175 + * @param object aManifest 1.176 + * The app's manifest. 1.177 + * @returns bool 1.178 + * Is permitted or not. 1.179 + **/ 1.180 + isSystemMessagePermittedToRegister: 1.181 + function isSystemMessagePermittedToRegister(aSysMsgName, aOrigin, aManifest) { 1.182 + debug("isSystemMessagePermittedToRegister(): " + 1.183 + "aSysMsgName: " + aSysMsgName + ", " + 1.184 + "aOrigin: " + aOrigin + ", " + 1.185 + "aManifest: " + JSON.stringify(aManifest)); 1.186 + 1.187 + let permNames = this.getSystemMessagePermissions(aSysMsgName); 1.188 + if (permNames === null) { 1.189 + return false; 1.190 + } 1.191 + 1.192 + // Check to see if the 'webapp' is app/privileged/certified. 1.193 + let appStatus; 1.194 + switch (AppsUtils.getAppManifestStatus(aManifest)) { 1.195 + case Ci.nsIPrincipal.APP_STATUS_CERTIFIED: 1.196 + appStatus = "certified"; 1.197 + break; 1.198 + case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED: 1.199 + appStatus = "privileged"; 1.200 + break; 1.201 + case Ci.nsIPrincipal.APP_STATUS_INSTALLED: 1.202 + appStatus = "app"; 1.203 + break; 1.204 + default: 1.205 + throw new Error("SystemMessagePermissionsChecker.jsm: " + 1.206 + "Cannot decide the app's status. Install cancelled."); 1.207 + break; 1.208 + } 1.209 + 1.210 + let newManifest = new ManifestHelper(aManifest, aOrigin); 1.211 + 1.212 + for (let permName in permNames) { 1.213 + // The app doesn't claim valid permissions for this sytem message. 1.214 + if (!newManifest.permissions || !newManifest.permissions[permName]) { 1.215 + debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " + 1.216 + "Please add the permission for app: '" + aOrigin + "'."); 1.217 + return false; 1.218 + } 1.219 + let permValue = PermissionsTable[permName][appStatus]; 1.220 + if (permValue != Ci.nsIPermissionManager.PROMPT_ACTION && 1.221 + permValue != Ci.nsIPermissionManager.ALLOW_ACTION) { 1.222 + debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " + 1.223 + "Please add the permission for app: '" + aOrigin + "'."); 1.224 + return false; 1.225 + } 1.226 + 1.227 + // Compare the expanded permission names between the ones in 1.228 + // app's manifest and the ones needed for system message. 1.229 + let expandedPermNames = 1.230 + expandPermissions(permName, 1.231 + newManifest.permissions[permName].access); 1.232 + 1.233 + let permNamesWithAccess = permNames[permName]; 1.234 + 1.235 + // Early return false as soon as any permission is not matched. 1.236 + for (let idx in permNamesWithAccess) { 1.237 + let index = expandedPermNames.indexOf(permNamesWithAccess[idx]); 1.238 + if (index == -1) { 1.239 + debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " + 1.240 + "Please add the permission for app: '" + aOrigin + "'."); 1.241 + return false; 1.242 + } 1.243 + } 1.244 + } 1.245 + 1.246 + // All the permissions needed for this system message are matched. 1.247 + return true; 1.248 + }, 1.249 + 1.250 + /** 1.251 + * Check if the system message is permitted to be sent to the given 1.252 + * app's page at run-time based on the current app's permissions. 1.253 + * @param string aSysMsgName 1.254 + * The system messsage name. 1.255 + * @param string aPageURL 1.256 + * The app's page URL. 1.257 + * @param string aManifestURL 1.258 + * The app's manifest URL. 1.259 + * @returns bool 1.260 + * Is permitted or not. 1.261 + **/ 1.262 + isSystemMessagePermittedToSend: 1.263 + function isSystemMessagePermittedToSend(aSysMsgName, aPageURL, aManifestURL) { 1.264 + debug("isSystemMessagePermittedToSend(): " + 1.265 + "aSysMsgName: " + aSysMsgName + ", " + 1.266 + "aPageURL: " + aPageURL + ", " + 1.267 + "aManifestURL: " + aManifestURL); 1.268 + 1.269 + let permNames = this.getSystemMessagePermissions(aSysMsgName); 1.270 + if (permNames === null) { 1.271 + return false; 1.272 + } 1.273 + 1.274 + let pageURI = Services.io.newURI(aPageURL, null, null); 1.275 + for (let permName in permNames) { 1.276 + let permNamesWithAccess = permNames[permName]; 1.277 + 1.278 + // Early return false as soon as any permission is not matched. 1.279 + for (let idx in permNamesWithAccess) { 1.280 + if(PermissionSettingsModule.getPermission(permNamesWithAccess[idx], 1.281 + aManifestURL, 1.282 + pageURI.prePath, 1.283 + false) != "allow") { 1.284 + debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " + 1.285 + "Please add the permission for app: '" + pageURI.prePath + "'."); 1.286 + return false; 1.287 + } 1.288 + } 1.289 + } 1.290 + 1.291 + // All the permissions needed for this system message are matched. 1.292 + return true; 1.293 + } 1.294 +};