2012-12-05 03:49:16 +00:00
|
|
|
/* 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;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
Cu.import("resource://gre/modules/AppsUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
|
2012-12-15 01:32:30 +00:00
|
|
|
Cu.import("resource://gre/modules/PermissionsTable.jsm");
|
2012-12-05 03:49:16 +00:00
|
|
|
Cu.import("resource://gre/modules/PermissionSettings.jsm");
|
|
|
|
|
2014-10-20 19:47:12 +00:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
|
|
|
"@mozilla.org/datastore-service;1",
|
|
|
|
"nsIDataStoreService");
|
|
|
|
|
2012-12-05 03:49:16 +00:00
|
|
|
this.EXPORTED_SYMBOLS = ["SystemMessagePermissionsChecker",
|
2014-10-20 19:47:12 +00:00
|
|
|
"SystemMessagePermissionsTable"];
|
2012-12-05 03:49:16 +00:00
|
|
|
|
|
|
|
function debug(aStr) {
|
|
|
|
// dump("SystemMessagePermissionsChecker.jsm: " + aStr + "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// This table maps system message to permission(s), indicating only
|
|
|
|
// the system messages granted by the page's permissions are allowed
|
|
|
|
// to be registered or sent to that page. Note the empty permission
|
|
|
|
// set means this type of system message is always permitted.
|
|
|
|
|
|
|
|
this.SystemMessagePermissionsTable = {
|
|
|
|
"activity": { },
|
|
|
|
"alarm": {
|
|
|
|
"alarms": []
|
|
|
|
},
|
|
|
|
"bluetooth-dialer-command": {
|
|
|
|
"telephony": []
|
|
|
|
},
|
|
|
|
"bluetooth-cancel": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
2013-08-12 09:32:25 +00:00
|
|
|
"bluetooth-hid-status-changed": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
2013-05-20 07:34:45 +00:00
|
|
|
"bluetooth-pairing-request": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
2012-12-05 03:49:16 +00:00
|
|
|
"bluetooth-opp-transfer-complete": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
|
|
|
"bluetooth-opp-update-progress": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
|
|
|
"bluetooth-opp-receiving-file-confirmation": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
|
|
|
"bluetooth-opp-transfer-start": {
|
|
|
|
"bluetooth": []
|
|
|
|
},
|
2014-08-20 11:17:34 +00:00
|
|
|
"cellbroadcast-received": {
|
|
|
|
"cellbroadcast": []
|
|
|
|
},
|
2013-08-16 09:49:53 +00:00
|
|
|
"connection": { },
|
2014-05-23 06:19:03 +00:00
|
|
|
"captive-portal": {
|
|
|
|
"wifi-manage": []
|
|
|
|
},
|
2013-10-18 10:44:25 +00:00
|
|
|
"dummy-system-message": { }, // for system message testing framework
|
2012-12-05 03:49:16 +00:00
|
|
|
"headset-button": { },
|
|
|
|
"icc-stkcommand": {
|
|
|
|
"settings": ["read", "write"]
|
|
|
|
},
|
2013-08-02 06:37:31 +00:00
|
|
|
"media-button": { },
|
2013-05-31 05:21:29 +00:00
|
|
|
"networkstats-alarm": {
|
|
|
|
"networkstats-manage": []
|
|
|
|
},
|
2012-12-05 03:49:16 +00:00
|
|
|
"notification": {
|
|
|
|
"desktop-notification": []
|
|
|
|
},
|
2013-03-29 03:49:41 +00:00
|
|
|
"push": {
|
|
|
|
"push": []
|
|
|
|
},
|
|
|
|
"push-register": {
|
|
|
|
"push": []
|
|
|
|
},
|
2015-01-13 09:53:14 +00:00
|
|
|
"request-sync": { },
|
2013-11-01 09:55:54 +00:00
|
|
|
"sms-delivery-success": {
|
|
|
|
"sms": []
|
|
|
|
},
|
2013-11-25 10:54:59 +00:00
|
|
|
"sms-read-success": {
|
|
|
|
"sms": []
|
|
|
|
},
|
2012-12-05 03:49:16 +00:00
|
|
|
"sms-received": {
|
|
|
|
"sms": []
|
|
|
|
},
|
2012-12-21 12:30:52 +00:00
|
|
|
"sms-sent": {
|
|
|
|
"sms": []
|
|
|
|
},
|
2012-12-05 03:49:16 +00:00
|
|
|
"telephony-new-call": {
|
|
|
|
"telephony": []
|
2012-12-16 12:25:02 +00:00
|
|
|
},
|
2012-12-18 13:54:18 +00:00
|
|
|
"telephony-call-ended": {
|
|
|
|
"telephony": []
|
|
|
|
},
|
2012-12-16 12:25:02 +00:00
|
|
|
"ussd-received": {
|
|
|
|
"mobileconnection": []
|
2013-06-17 08:37:59 +00:00
|
|
|
},
|
|
|
|
"wappush-received": {
|
2013-08-05 07:21:07 +00:00
|
|
|
"wappush": []
|
2013-06-17 08:37:59 +00:00
|
|
|
},
|
2013-09-10 16:48:19 +00:00
|
|
|
"cdma-info-rec-received": {
|
|
|
|
"mobileconnection": []
|
|
|
|
},
|
2014-08-27 12:41:00 +00:00
|
|
|
"nfc-hci-event-transaction": {
|
|
|
|
"nfc-hci-events": []
|
|
|
|
},
|
2013-11-05 01:17:05 +00:00
|
|
|
"nfc-manager-tech-discovered": {
|
|
|
|
"nfc-manager": []
|
|
|
|
},
|
|
|
|
"nfc-manager-tech-lost": {
|
|
|
|
"nfc-manager": []
|
|
|
|
},
|
2013-12-15 23:22:27 +00:00
|
|
|
"nfc-manager-send-file": {
|
|
|
|
"nfc-manager": []
|
|
|
|
},
|
2015-03-04 16:02:34 +00:00
|
|
|
"wifip2p-pairing-request": {
|
|
|
|
"wifi-manage": []
|
|
|
|
},
|
2014-03-11 15:55:55 +00:00
|
|
|
"first-run-with-sim": {
|
|
|
|
"settings": ["read", "write"]
|
|
|
|
}
|
2012-12-05 03:49:16 +00:00
|
|
|
};
|
|
|
|
|
2014-06-27 07:58:47 +00:00
|
|
|
|
2012-12-05 03:49:16 +00:00
|
|
|
this.SystemMessagePermissionsChecker = {
|
|
|
|
/**
|
|
|
|
* Return all the needed permission names for the given system message.
|
|
|
|
* @param string aSysMsgName
|
|
|
|
* The system messsage name.
|
|
|
|
* @returns object
|
|
|
|
* Format: { permName (string): permNamesWithAccess (string array), ... }
|
|
|
|
* Ex, { "settings": ["settings-read", "settings-write"], ... }.
|
|
|
|
* Note: an empty object will be returned if it's always permitted.
|
|
|
|
* @returns null
|
|
|
|
* Return and report error when any unexpected error is ecountered.
|
|
|
|
* Ex, when the system message we want to search is not included.
|
|
|
|
**/
|
|
|
|
getSystemMessagePermissions: function getSystemMessagePermissions(aSysMsgName) {
|
|
|
|
debug("getSystemMessagePermissions(): aSysMsgName: " + aSysMsgName);
|
|
|
|
|
|
|
|
let permNames = SystemMessagePermissionsTable[aSysMsgName];
|
|
|
|
if (permNames === undefined) {
|
2014-10-20 19:47:12 +00:00
|
|
|
debug("'" + aSysMsgName + "' is not associated with permissions. " +
|
|
|
|
"Please add them to the SystemMessage[Prefix]PermissionsTable.");
|
|
|
|
return null;
|
2012-12-05 03:49:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let object = { };
|
|
|
|
for (let permName in permNames) {
|
|
|
|
if (PermissionsTable[permName] === undefined) {
|
|
|
|
debug("'" + permName + "' for '" + aSysMsgName + "' is invalid. " +
|
2014-06-27 07:58:47 +00:00
|
|
|
"Please correct it in the SystemMessage[Prefix]PermissionsTable.");
|
2012-12-05 03:49:16 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct a new permission name array by adding the access suffixes.
|
|
|
|
let access = permNames[permName];
|
|
|
|
if (!access || !Array.isArray(access)) {
|
|
|
|
debug("'" + permName + "' is not associated with access array. " +
|
2014-06-27 07:58:47 +00:00
|
|
|
"Please correct it in the SystemMessage[Prefix]PermissionsTable.");
|
2012-12-05 03:49:16 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
object[permName] = appendAccessToPermName(permName, access);
|
|
|
|
}
|
|
|
|
return object
|
|
|
|
},
|
|
|
|
|
2014-10-20 19:47:12 +00:00
|
|
|
/**
|
|
|
|
* Check if the message is a datastore-update message
|
|
|
|
* @param string aSysMsgName
|
|
|
|
* The system messsage name.
|
|
|
|
*/
|
|
|
|
isDataStoreSystemMessage: function(aSysMsgName) {
|
|
|
|
return aSysMsgName.indexOf('datastore-update-') === 0;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if this manifest can deliver this particular datastore message.
|
|
|
|
*/
|
|
|
|
canDeliverDataStoreSystemMessage: function(aSysMsgName, aManifestURL) {
|
|
|
|
let store = aSysMsgName.substr('datastore-update-'.length);
|
|
|
|
|
|
|
|
// Get all the manifest URLs of the apps which can access the datastore.
|
|
|
|
let manifestURLs = dataStoreService.getAppManifestURLsForDataStore(store);
|
|
|
|
let enumerate = manifestURLs.enumerate();
|
|
|
|
while (enumerate.hasMoreElements()) {
|
|
|
|
let manifestURL = enumerate.getNext().QueryInterface(Ci.nsISupportsString);
|
|
|
|
if (manifestURL == aManifestURL) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
2012-12-05 03:49:16 +00:00
|
|
|
/**
|
|
|
|
* Check if the system message is permitted to be registered for the given
|
|
|
|
* app at start-up based on the permissions claimed in the app's manifest.
|
|
|
|
* @param string aSysMsgName
|
|
|
|
* The system messsage name.
|
2014-07-30 21:00:15 +00:00
|
|
|
* @param string aManifestURL
|
|
|
|
* The app's manifest URL.
|
2012-12-05 03:49:16 +00:00
|
|
|
* @param object aManifest
|
|
|
|
* The app's manifest.
|
|
|
|
* @returns bool
|
|
|
|
* Is permitted or not.
|
|
|
|
**/
|
|
|
|
isSystemMessagePermittedToRegister:
|
2014-07-30 21:00:15 +00:00
|
|
|
function isSystemMessagePermittedToRegister(aSysMsgName,
|
|
|
|
aManifestURL,
|
|
|
|
aManifest) {
|
2012-12-05 03:49:16 +00:00
|
|
|
debug("isSystemMessagePermittedToRegister(): " +
|
|
|
|
"aSysMsgName: " + aSysMsgName + ", " +
|
2014-07-30 21:00:15 +00:00
|
|
|
"aManifestURL: " + aManifestURL + ", " +
|
2012-12-05 03:49:16 +00:00
|
|
|
"aManifest: " + JSON.stringify(aManifest));
|
|
|
|
|
2014-10-20 19:47:12 +00:00
|
|
|
if (this.isDataStoreSystemMessage(aSysMsgName) &&
|
|
|
|
this.canDeliverDataStoreSystemMessage(aSysMsgName, aManifestURL)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-05 03:49:16 +00:00
|
|
|
let permNames = this.getSystemMessagePermissions(aSysMsgName);
|
|
|
|
if (permNames === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check to see if the 'webapp' is app/privileged/certified.
|
|
|
|
let appStatus;
|
|
|
|
switch (AppsUtils.getAppManifestStatus(aManifest)) {
|
|
|
|
case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
|
|
|
|
appStatus = "certified";
|
|
|
|
break;
|
|
|
|
case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
|
|
|
|
appStatus = "privileged";
|
|
|
|
break;
|
|
|
|
case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
|
|
|
|
appStatus = "app";
|
2014-09-16 20:14:02 +00:00
|
|
|
if (aManifest.type == "trusted") {
|
|
|
|
appStatus = "trusted";
|
|
|
|
}
|
2012-12-05 03:49:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Error("SystemMessagePermissionsChecker.jsm: " +
|
|
|
|
"Cannot decide the app's status. Install cancelled.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-07-30 21:00:15 +00:00
|
|
|
// It's ok here to not pass the origin to ManifestHelper since we only
|
|
|
|
// need the permission property and that doesn't depend on uri resolution.
|
|
|
|
let newManifest = new ManifestHelper(aManifest, aManifestURL, aManifestURL);
|
2012-12-05 03:49:16 +00:00
|
|
|
|
|
|
|
for (let permName in permNames) {
|
|
|
|
// The app doesn't claim valid permissions for this sytem message.
|
|
|
|
if (!newManifest.permissions || !newManifest.permissions[permName]) {
|
|
|
|
debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
|
2014-07-30 21:00:15 +00:00
|
|
|
"Please add the permission for app: '" + aManifestURL + "'.");
|
2012-12-05 03:49:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
let permValue = PermissionsTable[permName][appStatus];
|
|
|
|
if (permValue != Ci.nsIPermissionManager.PROMPT_ACTION &&
|
|
|
|
permValue != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
|
|
|
debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
|
2014-07-30 21:00:15 +00:00
|
|
|
"Please add the permission for app: '" + aManifestURL + "'.");
|
2012-12-05 03:49:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compare the expanded permission names between the ones in
|
|
|
|
// app's manifest and the ones needed for system message.
|
|
|
|
let expandedPermNames =
|
|
|
|
expandPermissions(permName,
|
2012-12-11 08:09:40 +00:00
|
|
|
newManifest.permissions[permName].access);
|
2012-12-05 03:49:16 +00:00
|
|
|
|
|
|
|
let permNamesWithAccess = permNames[permName];
|
|
|
|
|
|
|
|
// Early return false as soon as any permission is not matched.
|
|
|
|
for (let idx in permNamesWithAccess) {
|
|
|
|
let index = expandedPermNames.indexOf(permNamesWithAccess[idx]);
|
|
|
|
if (index == -1) {
|
|
|
|
debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
|
|
|
|
"Please add the permission for app: '" + aOrigin + "'.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// All the permissions needed for this system message are matched.
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the system message is permitted to be sent to the given
|
|
|
|
* app's page at run-time based on the current app's permissions.
|
|
|
|
* @param string aSysMsgName
|
|
|
|
* The system messsage name.
|
2014-03-31 08:04:36 +00:00
|
|
|
* @param string aPageURL
|
|
|
|
* The app's page URL.
|
2012-12-05 03:49:16 +00:00
|
|
|
* @param string aManifestURL
|
|
|
|
* The app's manifest URL.
|
|
|
|
* @returns bool
|
|
|
|
* Is permitted or not.
|
|
|
|
**/
|
|
|
|
isSystemMessagePermittedToSend:
|
2014-03-31 08:04:36 +00:00
|
|
|
function isSystemMessagePermittedToSend(aSysMsgName, aPageURL, aManifestURL) {
|
2012-12-05 03:49:16 +00:00
|
|
|
debug("isSystemMessagePermittedToSend(): " +
|
|
|
|
"aSysMsgName: " + aSysMsgName + ", " +
|
2014-03-31 08:04:36 +00:00
|
|
|
"aPageURL: " + aPageURL + ", " +
|
2012-12-05 03:49:16 +00:00
|
|
|
"aManifestURL: " + aManifestURL);
|
|
|
|
|
2014-10-20 19:47:12 +00:00
|
|
|
if (this.isDataStoreSystemMessage(aSysMsgName) &&
|
|
|
|
this.canDeliverDataStoreSystemMessage(aSysMsgName, aManifestURL)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-12-05 03:49:16 +00:00
|
|
|
let permNames = this.getSystemMessagePermissions(aSysMsgName);
|
|
|
|
if (permNames === null) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-31 08:04:36 +00:00
|
|
|
let pageURI = Services.io.newURI(aPageURL, null, null);
|
2012-12-05 03:49:16 +00:00
|
|
|
for (let permName in permNames) {
|
|
|
|
let permNamesWithAccess = permNames[permName];
|
|
|
|
|
|
|
|
// Early return false as soon as any permission is not matched.
|
|
|
|
for (let idx in permNamesWithAccess) {
|
|
|
|
if(PermissionSettingsModule.getPermission(permNamesWithAccess[idx],
|
|
|
|
aManifestURL,
|
|
|
|
pageURI.prePath,
|
|
|
|
false) != "allow") {
|
|
|
|
debug("'" + aSysMsgName + "' isn't permitted by '" + permName + "'. " +
|
|
|
|
"Please add the permission for app: '" + pageURI.prePath + "'.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// All the permissions needed for this system message are matched.
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|