mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Bug 1179718 - Add a CheckAllPermissions extended attribute to WebIDL. r=bz
This commit is contained in:
parent
5da5ad2aec
commit
a5886f19c7
@ -2436,6 +2436,28 @@ CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[])
|
||||
{
|
||||
JS::Rooted<JSObject*> rootedObj(aCx, aObj);
|
||||
nsPIDOMWindow* window = xpc::WindowGlobalOrNull(rootedObj);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE(permMgr, false);
|
||||
|
||||
do {
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
permMgr->TestPermissionFromWindow(window, *aPermissions, &permission);
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
return false;
|
||||
}
|
||||
} while (*(++aPermissions));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
HandlePrerenderingViolation(nsPIDOMWindow* aWindow)
|
||||
{
|
||||
|
@ -3096,6 +3096,11 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
|
||||
bool
|
||||
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
// Returns true if aObj's global has all of the permissions named in aPermissions
|
||||
// set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
|
||||
bool
|
||||
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
// This function is called by the bindings layer for methods/getters/setters
|
||||
// that are not safe to be called in prerendering mode. It checks to make sure
|
||||
// that the |this| object is not running in a global that is in prerendering
|
||||
|
@ -1895,11 +1895,12 @@ class MemberCondition:
|
||||
None, they should be strings that have the pref name (for "pref")
|
||||
or function name (for "func" and "available").
|
||||
"""
|
||||
def __init__(self, pref, func, available=None, checkPermissions=None):
|
||||
def __init__(self, pref, func, available=None, checkPermissions=None, checkAllPermissions=None):
|
||||
assert pref is None or isinstance(pref, str)
|
||||
assert func is None or isinstance(func, str)
|
||||
assert available is None or isinstance(available, str)
|
||||
assert checkPermissions is None or isinstance(checkPermissions, int)
|
||||
assert checkAllPermissions is None or isinstance(checkAllPermissions, int)
|
||||
self.pref = pref
|
||||
|
||||
def toFuncPtr(val):
|
||||
@ -1912,11 +1913,16 @@ class MemberCondition:
|
||||
self.checkPermissions = "nullptr"
|
||||
else:
|
||||
self.checkPermissions = "permissions_%i" % checkPermissions
|
||||
if checkAllPermissions is None:
|
||||
self.checkAllPermissions = "nullptr"
|
||||
else:
|
||||
self.checkAllPermissions = "allpermissions_%i" % checkAllPermissions
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.pref == other.pref and self.func == other.func and
|
||||
self.available == other.available and
|
||||
self.checkPermissions == other.checkPermissions)
|
||||
self.checkPermissions == other.checkPermissions and
|
||||
self.checkAllPermissions == other.checkAllPermissions)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
@ -1984,7 +1990,8 @@ class PropertyDefiner:
|
||||
PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Func"),
|
||||
getAvailableInTestFunc(interfaceMember),
|
||||
descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
|
||||
descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name),
|
||||
descriptor.checkAllPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
|
||||
|
||||
def generatePrefableArray(self, array, name, specFormatter, specTerminator,
|
||||
specType, getCondition, getDataTuple, doIdArrays):
|
||||
@ -2022,7 +2029,7 @@ class PropertyDefiner:
|
||||
specs = []
|
||||
prefableSpecs = []
|
||||
|
||||
prefableTemplate = ' { true, %s, %s, %s, &%s[%d] }'
|
||||
prefableTemplate = ' { true, %s, %s, %s, %s, &%s[%d] }'
|
||||
prefCacheTemplate = '&%s[%d].enabled'
|
||||
|
||||
def switchToCondition(props, condition):
|
||||
@ -2037,6 +2044,7 @@ class PropertyDefiner:
|
||||
(condition.func,
|
||||
condition.available,
|
||||
condition.checkPermissions,
|
||||
condition.checkAllPermissions,
|
||||
name + "_specs", len(specs)))
|
||||
|
||||
switchToCondition(self, lastCondition)
|
||||
@ -3170,6 +3178,9 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
checkPermissions = self.descriptor.checkPermissionsIndex
|
||||
if checkPermissions is not None:
|
||||
conditions.append("CheckPermissions(aCx, aObj, permissions_%i)" % checkPermissions)
|
||||
checkAllPermissions = self.descriptor.checkAllPermissionsIndex
|
||||
if checkAllPermissions is not None:
|
||||
conditions.append("CheckAllPermissions(aCx, aObj, allpermissions_%i)" % checkAllPermissions)
|
||||
# We should really have some conditions
|
||||
assert len(body) or len(conditions)
|
||||
|
||||
@ -11436,14 +11447,16 @@ class CGDescriptor(CGThing):
|
||||
if descriptor.concrete and descriptor.wrapperCache:
|
||||
cgThings.append(CGClassObjectMovedHook(descriptor))
|
||||
|
||||
if len(descriptor.permissions):
|
||||
for (k, v) in sorted(descriptor.permissions.items()):
|
||||
perms = CGList((CGGeneric('"%s",' % p) for p in k), joiner="\n")
|
||||
perms.append(CGGeneric("nullptr"))
|
||||
cgThings.append(CGWrapper(CGIndenter(perms),
|
||||
pre="static const char* const permissions_%i[] = {\n" % v,
|
||||
post="\n};\n",
|
||||
defineOnly=True))
|
||||
for name in ["permissions", "allpermissions"]:
|
||||
permissions = getattr(descriptor, name)
|
||||
if len(permissions):
|
||||
for (k, v) in sorted(permissions.items()):
|
||||
perms = CGList((CGGeneric('"%s",' % p) for p in k), joiner="\n")
|
||||
perms.append(CGGeneric("nullptr"))
|
||||
cgThings.append(CGWrapper(CGIndenter(perms),
|
||||
pre="static const char* const %s_%i[] = {\n" % (name, v),
|
||||
post="\n};\n",
|
||||
defineOnly=True))
|
||||
|
||||
# Generate the _ClearCachedFooValue methods before the property arrays that use them.
|
||||
if descriptor.interface.isJSImplemented():
|
||||
|
@ -547,10 +547,16 @@ class Descriptor(DescriptorProvider):
|
||||
|
||||
if not self.interface.isExternal():
|
||||
self.permissions = dict()
|
||||
self.allpermissions = dict()
|
||||
|
||||
# Adds a permission list to this descriptor and returns the index to use.
|
||||
def addPermissions(ifaceOrMember):
|
||||
checkPermissions = ifaceOrMember.getExtendedAttribute("CheckPermissions")
|
||||
def addPermissions(ifaceOrMember, attribute):
|
||||
if attribute == "CheckAllPermissions":
|
||||
permissions = self.allpermissions
|
||||
else:
|
||||
permissions = self.permissions
|
||||
|
||||
checkPermissions = ifaceOrMember.getExtendedAttribute(attribute)
|
||||
if checkPermissions is None:
|
||||
return None
|
||||
|
||||
@ -560,17 +566,22 @@ class Descriptor(DescriptorProvider):
|
||||
checkPermissions = checkPermissions[0]
|
||||
permissionsList = checkPermissions.split()
|
||||
if len(permissionsList) == 0:
|
||||
raise TypeError("Need at least one permission name for CheckPermissions")
|
||||
raise TypeError("Need at least one permission name for %s" % attribute)
|
||||
|
||||
permissionsList = tuple(sorted(set(permissionsList)))
|
||||
return self.permissions.setdefault(permissionsList, len(self.permissions))
|
||||
return permissions.setdefault(permissionsList, len(permissions))
|
||||
|
||||
self.checkPermissionsIndex = addPermissions(self.interface)
|
||||
self.checkPermissionsIndex = addPermissions(self.interface, "CheckPermissions")
|
||||
self.checkPermissionsIndicesForMembers = dict()
|
||||
self.checkAllPermissionsIndex = addPermissions(self.interface, "CheckAllPermissions")
|
||||
self.checkAllPermissionsIndicesForMembers = dict()
|
||||
for m in self.interface.members:
|
||||
permissionsIndex = addPermissions(m)
|
||||
permissionsIndex = addPermissions(m, "CheckPermissions")
|
||||
if permissionsIndex is not None:
|
||||
self.checkPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex
|
||||
allpermissionsIndex = addPermissions(m, "CheckAllPermissions")
|
||||
if allpermissionsIndex is not None:
|
||||
self.checkAllPermissionsIndicesForMembers[m.identifier.name] = allpermissionsIndex
|
||||
|
||||
def isTestInterface(iface):
|
||||
return (iface.identifier.name in ["TestInterface",
|
||||
@ -580,6 +591,7 @@ class Descriptor(DescriptorProvider):
|
||||
self.featureDetectibleThings = set()
|
||||
if not isTestInterface(self.interface):
|
||||
if (self.interface.getExtendedAttribute("CheckPermissions") or
|
||||
self.interface.getExtendedAttribute("CheckAllPermissions") or
|
||||
self.interface.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
|
||||
if self.interface.getNavigatorProperty():
|
||||
self.featureDetectibleThings.add("Navigator.%s" % self.interface.getNavigatorProperty())
|
||||
@ -591,6 +603,7 @@ class Descriptor(DescriptorProvider):
|
||||
|
||||
for m in self.interface.members:
|
||||
if (m.getExtendedAttribute("CheckPermissions") or
|
||||
m.getExtendedAttribute("CheckAllPermissions") or
|
||||
m.getExtendedAttribute("AvailableIn") == "PrivilegedApps"):
|
||||
self.featureDetectibleThings.add("%s.%s" % (self.interface.identifier.name, m.identifier.name))
|
||||
|
||||
|
@ -42,6 +42,9 @@ typedef bool
|
||||
bool
|
||||
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
bool
|
||||
CheckAllPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
struct ConstantSpec
|
||||
{
|
||||
const char* name;
|
||||
@ -56,7 +59,7 @@ struct Prefable {
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
if (!enabledFunc && !availableFunc && !checkPermissions) {
|
||||
if (!enabledFunc && !availableFunc && !checkPermissions && !checkAllPermissions) {
|
||||
return true;
|
||||
}
|
||||
if (enabledFunc &&
|
||||
@ -72,6 +75,11 @@ struct Prefable {
|
||||
checkPermissions)) {
|
||||
return false;
|
||||
}
|
||||
if (checkAllPermissions &&
|
||||
!CheckAllPermissions(cx, js::GetGlobalForObjectCrossCompartment(obj),
|
||||
checkAllPermissions)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -87,6 +95,7 @@ struct Prefable {
|
||||
// implementations in case when we need to do two separate checks.
|
||||
PropertyEnabled availableFunc;
|
||||
const char* const* checkPermissions;
|
||||
const char* const* checkAllPermissions;
|
||||
// Array of specs, terminated in whatever way is customary for T.
|
||||
// Null to indicate a end-of-array for Prefable, when such an
|
||||
// indicator is needed.
|
||||
|
@ -1134,7 +1134,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
member.getExtendedAttribute("Pref") or
|
||||
member.getExtendedAttribute("Func") or
|
||||
member.getExtendedAttribute("AvailableIn") or
|
||||
member.getExtendedAttribute("CheckPermissions")):
|
||||
member.getExtendedAttribute("CheckPermissions") or
|
||||
member.getExtendedAttribute("CheckAllPermissions")):
|
||||
raise WebIDLError("[Alias] must not be used on a "
|
||||
"conditionally exposed operation",
|
||||
[member.location])
|
||||
@ -1166,12 +1167,13 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
self.parentScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
if (self.getExtendedAttribute("CheckPermissions") and
|
||||
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
|
||||
raise WebIDLError("[CheckPermissions] used on an interface that is "
|
||||
"not %s-only" %
|
||||
self.parentScope.primaryGlobalName,
|
||||
[self.location])
|
||||
for attribute in ["CheckPermissions", "CheckAllPermissions"]:
|
||||
if (self.getExtendedAttribute(attribute) and
|
||||
self._exposureGlobalNames != set([self.parentScope.primaryGlobalName])):
|
||||
raise WebIDLError("[%s] used on an interface that is "
|
||||
"not %s-only" %
|
||||
(attribute, self.parentScope.primaryGlobalName),
|
||||
[self.location])
|
||||
|
||||
# Conditional exposure makes no sense for interfaces with no
|
||||
# interface object, unless they're navigator properties.
|
||||
@ -1385,7 +1387,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
identifier == "NavigatorProperty" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "Func" or
|
||||
identifier == "CheckPermissions"):
|
||||
identifier == "CheckPermissions" or
|
||||
identifier == "CheckAllPermissions"):
|
||||
# Known extended attributes that take a string value
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[%s] must have a value" % identifier,
|
||||
@ -1513,7 +1516,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins):
|
||||
self.getExtendedAttribute("ChromeOnly") or
|
||||
self.getExtendedAttribute("Func") or
|
||||
self.getExtendedAttribute("AvailableIn") or
|
||||
self.getExtendedAttribute("CheckPermissions"))
|
||||
self.getExtendedAttribute("CheckPermissions") or
|
||||
self.getExtendedAttribute("CheckAllPermissions"))
|
||||
|
||||
class IDLDictionary(IDLObjectWithScope):
|
||||
def __init__(self, location, parentScope, name, parent, members):
|
||||
@ -3361,12 +3365,13 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
|
||||
"%s-only" % self._globalScope.primaryGlobalName,
|
||||
[self.location])
|
||||
|
||||
if (self.getExtendedAttribute("CheckPermissions") and
|
||||
self.exposureSet != set([self._globalScope.primaryGlobalName])):
|
||||
raise WebIDLError("[CheckPermissions] used on an interface member "
|
||||
"that is not %s-only" %
|
||||
self._globalScope.primaryGlobalName,
|
||||
[self.location])
|
||||
for attribute in ["CheckPermissions", "CheckAllPermissions"]:
|
||||
if (self.getExtendedAttribute(attribute) and
|
||||
self.exposureSet != set([self._globalScope.primaryGlobalName])):
|
||||
raise WebIDLError("[%s] used on an interface member that is "
|
||||
"not %s-only" %
|
||||
(attribute, self.parentScope.primaryGlobalName),
|
||||
[self.location])
|
||||
|
||||
if self.isAttr() or self.isMethod():
|
||||
if self.affects == "Everything" and self.dependsOn != "Everything":
|
||||
@ -3707,7 +3712,8 @@ class IDLConst(IDLInterfaceMember):
|
||||
identifier == "ChromeOnly" or
|
||||
identifier == "Func" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "CheckPermissions"):
|
||||
identifier == "CheckPermissions" or
|
||||
identifier == "CheckAllPermissions"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
@ -3975,6 +3981,7 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
identifier == "NewObject" or
|
||||
identifier == "UnsafeInPrerendering" or
|
||||
identifier == "CheckPermissions" or
|
||||
identifier == "CheckAllPermissions" or
|
||||
identifier == "BinaryName"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
@ -4650,6 +4657,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
identifier == "Func" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "CheckPermissions" or
|
||||
identifier == "CheckAllPermissions" or
|
||||
identifier == "BinaryName" or
|
||||
identifier == "MethodIdentityTestable" or
|
||||
identifier == "StaticClassOverride"):
|
||||
|
Loading…
Reference in New Issue
Block a user