Bug 1179718 - Add a CheckAllPermissions extended attribute to WebIDL. r=bz

This commit is contained in:
Kan-Ru Chen 2015-07-03 16:03:35 +08:00
parent 5da5ad2aec
commit a5886f19c7
6 changed files with 105 additions and 35 deletions

View File

@ -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)
{

View File

@ -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

View File

@ -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():

View File

@ -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))

View File

@ -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.

View File

@ -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"):