зеркало из https://github.com/mozilla/gecko-dev.git
Bug 846200 - Support for granting settings permissions on a per-permission basis; r=bent
This commit is contained in:
Родитель
0ff3e02337
Коммит
9ef69caded
|
@ -30,20 +30,6 @@ function debug(aMsg) {
|
|||
//dump("-*-*- PermissionsInstaller.jsm : " + aMsg + "\n");
|
||||
}
|
||||
|
||||
// An array carring all the possible (expanded) permission names.
|
||||
let AllPossiblePermissions = [];
|
||||
for (let permName in PermissionsTable) {
|
||||
let expandedPermNames = [];
|
||||
if (PermissionsTable[permName].access) {
|
||||
expandedPermNames = expandPermissions(permName, READWRITE);
|
||||
} else {
|
||||
expandedPermNames = expandPermissions(permName);
|
||||
}
|
||||
AllPossiblePermissions = AllPossiblePermissions.concat(expandedPermNames);
|
||||
AllPossiblePermissions =
|
||||
AllPossiblePermissions.concat(["offline-app", "pin-app"]);
|
||||
}
|
||||
|
||||
this.PermissionsInstaller = {
|
||||
/**
|
||||
* Install permissisions or remove deprecated permissions upon re-install.
|
||||
|
|
|
@ -12,7 +12,8 @@ this.EXPORTED_SYMBOLS = [
|
|||
"PermissionsReverseTable",
|
||||
"expandPermissions",
|
||||
"appendAccessToPermName",
|
||||
"isExplicitInPermissionsTable"
|
||||
"isExplicitInPermissionsTable",
|
||||
"AllPossiblePermissions"
|
||||
];
|
||||
|
||||
// Permission access flags
|
||||
|
@ -144,7 +145,7 @@ this.PermissionsTable = { geolocation: {
|
|||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION,
|
||||
access: ["read", "write"],
|
||||
additional: ["indexedDB-chrome-settings"]
|
||||
additional: ["indexedDB-chrome-settings", "settings-api"]
|
||||
},
|
||||
permissions: {
|
||||
app: DENY_ACTION,
|
||||
|
@ -491,7 +492,10 @@ this.expandPermissions = function expandPermissions(aPermName, aAccess) {
|
|||
return expandedPermNames;
|
||||
};
|
||||
|
||||
this.PermissionsReverseTable = (function () {
|
||||
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
|
||||
|
@ -499,8 +503,9 @@ this.PermissionsReverseTable = (function () {
|
|||
// born. The idea is that
|
||||
// reverseTable[device-storage:music-read] should return
|
||||
// device-storage:music
|
||||
let reverseTable = {};
|
||||
|
||||
//
|
||||
// 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) {
|
||||
|
@ -509,12 +514,12 @@ this.PermissionsReverseTable = (function () {
|
|||
permAliases = expandPermissions(permName);
|
||||
}
|
||||
for (let i = 0; i < permAliases.length; i++) {
|
||||
reverseTable[permAliases[i]] = permName;
|
||||
PermissionsReverseTable[permAliases[i]] = permName;
|
||||
AllPossiblePermissions.push(permAliases[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return reverseTable;
|
||||
|
||||
AllPossiblePermissions =
|
||||
AllPossiblePermissions.concat(["offline-app", "pin-app"]);
|
||||
})();
|
||||
|
||||
this.isExplicitInPermissionsTable = function(aPermName, aIntStatus) {
|
||||
|
|
|
@ -2109,8 +2109,8 @@ Navigator::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
|||
}
|
||||
|
||||
if (name.EqualsLiteral("mozSettings")) {
|
||||
bool hasPermission = CheckPermission("settings-read") ||
|
||||
CheckPermission("settings-write");
|
||||
bool hasPermission = CheckPermission("settings-api-read") ||
|
||||
CheckPermission("settings-api-write");
|
||||
if (!hasPermission) {
|
||||
FillPropertyDescriptor(aDesc, aObject, JS::NullValue(), false);
|
||||
return true;
|
||||
|
|
|
@ -17,6 +17,7 @@ Cu.import("resource://gre/modules/SettingsQueue.jsm");
|
|||
Cu.import("resource://gre/modules/SettingsDB.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/PermissionsTable.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
|
@ -66,7 +67,7 @@ SettingsLock.prototype = {
|
|||
this._open = false;
|
||||
}.bind(lock);
|
||||
clearReq.onerror = function() {
|
||||
Services.DOMRequest.fireError(request, 0)
|
||||
Services.DOMRequest.fireError(request, 0);
|
||||
};
|
||||
break;
|
||||
case "set":
|
||||
|
@ -105,7 +106,7 @@ SettingsLock.prototype = {
|
|||
|
||||
setReq.onerror = function() {
|
||||
if (!request.error) {
|
||||
Services.DOMRequest.fireError(request, setReq.error.name)
|
||||
Services.DOMRequest.fireError(request, setReq.error.name);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -118,7 +119,7 @@ SettingsLock.prototype = {
|
|||
};
|
||||
checkKeyRequest.onerror = function(event) {
|
||||
if (!request.error) {
|
||||
Services.DOMRequest.fireError(request, checkKeyRequest.error.name)
|
||||
Services.DOMRequest.fireError(request, checkKeyRequest.error.name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ SettingsLock.prototype = {
|
|||
}.bind(lock);
|
||||
|
||||
getReq.onerror = function() {
|
||||
Services.DOMRequest.fireError(request, 0)
|
||||
Services.DOMRequest.fireError(request, 0);
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
@ -163,7 +164,7 @@ SettingsLock.prototype = {
|
|||
if (DEBUG) debug("database opened, creating transaction");
|
||||
|
||||
let manager = this._settingsManager;
|
||||
let transactionType = manager.hasWritePrivileges ? "readwrite" : "readonly";
|
||||
let transactionType = manager.hasAnyWritePrivileges ? "readwrite" : "readonly";
|
||||
|
||||
this._transaction =
|
||||
manager._settingsDB._db.transaction(SETTINGSSTORE_NAME, transactionType);
|
||||
|
@ -183,15 +184,14 @@ SettingsLock.prototype = {
|
|||
throw Components.results.NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
if (this._settingsManager.hasReadPrivileges) {
|
||||
if (!this._settingsManager.hasReadPermission("settings:" + aName)) {
|
||||
if (DEBUG) debug("get not allowed");
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
|
||||
this._requests.enqueue({ request: req, intent:"get", name: aName });
|
||||
this.maybeProcess();
|
||||
return req;
|
||||
} else {
|
||||
if (DEBUG) debug("get not allowed");
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
},
|
||||
|
||||
_serializePreservingBinaries: function _serializePreservingBinaries(aObject) {
|
||||
|
@ -232,25 +232,28 @@ SettingsLock.prototype = {
|
|||
throw "Settings lock not open";
|
||||
}
|
||||
|
||||
if (this._settingsManager.hasWritePrivileges) {
|
||||
// Check each requested permission to make sure we can set it
|
||||
let keys = Object.getOwnPropertyNames(aSettings);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (!this._settingsManager.hasWritePermission("settings:" + keys[i])) {
|
||||
if (DEBUG) debug("set not allowed on" + keys[i]);
|
||||
throw "No permission to call set on " + keys[i];
|
||||
}
|
||||
}
|
||||
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
|
||||
if (DEBUG) debug("send: " + JSON.stringify(aSettings));
|
||||
let settings = this._serializePreservingBinaries(aSettings);
|
||||
this._requests.enqueue({request: req, intent: "set", settings: settings});
|
||||
this.maybeProcess();
|
||||
return req;
|
||||
} else {
|
||||
if (DEBUG) debug("set not allowed");
|
||||
throw "No permission to call set";
|
||||
}
|
||||
},
|
||||
|
||||
clear: function clear() {
|
||||
if (!this._open) {
|
||||
throw "Settings lock not open";
|
||||
}
|
||||
|
||||
if (this._settingsManager.hasWritePrivileges) {
|
||||
// Only certified apps should be allowed to clear
|
||||
if (this._settingsManager.hasFullWritePrivileges) {
|
||||
let req = Services.DOMRequest.createRequest(this._settingsManager._window);
|
||||
this._requests.enqueue({ request: req, intent: "clear"});
|
||||
this.maybeProcess();
|
||||
|
@ -273,6 +276,7 @@ function SettingsManager() {
|
|||
|
||||
SettingsManager.prototype = {
|
||||
_callbacks: null,
|
||||
_perms: [],
|
||||
|
||||
_wrap: function _wrap(obj) {
|
||||
return Cu.cloneInto(obj, this._window);
|
||||
|
@ -340,9 +344,9 @@ SettingsManager.prototype = {
|
|||
removeObserver: function removeObserver(aName, aCallback) {
|
||||
if (DEBUG) debug("deleteObserver " + aName);
|
||||
if (this._callbacks && this._callbacks[aName]) {
|
||||
let index = this._callbacks[aName].indexOf(aCallback)
|
||||
let index = this._callbacks[aName].indexOf(aCallback);
|
||||
if (index != -1) {
|
||||
this._callbacks[aName].splice(index, 1)
|
||||
this._callbacks[aName].splice(index, 1);
|
||||
} else {
|
||||
if (DEBUG) debug("Callback not found for: " + aName);
|
||||
}
|
||||
|
@ -351,6 +355,14 @@ SettingsManager.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
hasReadPermission: function hasPermission(aName) {
|
||||
return this.hasFullReadPrivileges || this._perms.indexOf(aName + "-read") != -1;
|
||||
},
|
||||
|
||||
hasWritePermission: function hasPermission(aName) {
|
||||
return this.hasFullWritePrivileges || this._perms.indexOf(aName + "-write") != -1;
|
||||
},
|
||||
|
||||
init: function(aWindow) {
|
||||
mrm.registerStrongReporter(this);
|
||||
cpmm.addMessageListener("Settings:Change:Return:OK", this);
|
||||
|
@ -359,16 +371,34 @@ SettingsManager.prototype = {
|
|||
let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
this.innerWindowID = util.currentInnerWindowID;
|
||||
|
||||
let readPerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-read");
|
||||
let writePerm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "settings-write");
|
||||
this.hasReadPrivileges = readPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
this.hasWritePrivileges = writePerm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
if (this.hasReadPrivileges) {
|
||||
this.hasAnyWritePrivileges = false;
|
||||
|
||||
for (let idx in AllPossiblePermissions) {
|
||||
let permName = AllPossiblePermissions[idx];
|
||||
//Check to see if this is a settings permission. All settings permissions
|
||||
//begin with the word settings.
|
||||
if (permName.indexOf("settings") != 0) {
|
||||
continue;
|
||||
}
|
||||
if (Services.perms.testExactPermissionFromPrincipal(this._window.document.nodePrincipal, permName) == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
if(permName.indexOf("-write") > 0) {
|
||||
this.hasAnyWritePrivileges = true;
|
||||
}
|
||||
this._perms.push(permName);
|
||||
}
|
||||
}
|
||||
|
||||
this.hasFullReadPrivileges = this.hasReadPermission("settings");
|
||||
this.hasFullWritePrivileges = this.hasWritePermission("settings");
|
||||
|
||||
if (this.hasFullReadPrivileges) {
|
||||
cpmm.sendAsyncMessage("Settings:RegisterForMessages");
|
||||
}
|
||||
|
||||
if (!this.hasReadPrivileges && !this.hasWritePrivileges) {
|
||||
// settings-api is an additional setting on all settings permissions. This
|
||||
// is how we can figure out whether to expose the mozSettings DOM object.
|
||||
if (!this.hasReadPermission("settings-api") && !this.hasWritePermission("settings-api")) {
|
||||
dump("No settings permission for: " + aWindow.document.nodePrincipal.origin + "\n");
|
||||
Cu.reportError("No settings permission for: " + aWindow.document.nodePrincipal.origin);
|
||||
}
|
||||
|
@ -426,4 +456,4 @@ SettingsManager.prototype = {
|
|||
Ci.nsIMemoryReporter]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock])
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SettingsManager, SettingsLock]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче