mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 952486 - Add a CheckPermissions extended attribute to WebIDL. r=bz
This commit is contained in:
parent
f4045bcb86
commit
5a17903f23
@ -339,6 +339,7 @@ public:
|
||||
|
||||
// public methods
|
||||
nsPIDOMWindow* GetPrivateParent();
|
||||
|
||||
// callback for close event
|
||||
void ReallyCloseWindow();
|
||||
|
||||
|
@ -20,7 +20,9 @@
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "WrapperFactory.h"
|
||||
@ -2228,6 +2230,28 @@ EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
|
||||
return JS_EnumerateStandardClasses(aCx, aObj);
|
||||
}
|
||||
|
||||
bool
|
||||
CheckPermissions(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 true;
|
||||
}
|
||||
} while (*(++aPermissions));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
|
@ -2828,6 +2828,11 @@ AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
|
||||
JS::Handle<JS::Value> aValue);
|
||||
#endif
|
||||
|
||||
// Returns true if aObj's global has any of the permissions named in aPermissions
|
||||
// set to nsIPermissionManager::ALLOW_ACTION. aPermissions must be null-terminated.
|
||||
bool
|
||||
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -1797,10 +1797,11 @@ 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):
|
||||
def __init__(self, pref, func, available=None, checkPermissions=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)
|
||||
self.pref = pref
|
||||
|
||||
def toFuncPtr(val):
|
||||
@ -1809,10 +1810,15 @@ class MemberCondition:
|
||||
return "&" + val
|
||||
self.func = toFuncPtr(func)
|
||||
self.available = toFuncPtr(available)
|
||||
if checkPermissions is None:
|
||||
self.checkPermissions = "nullptr"
|
||||
else:
|
||||
self.checkPermissions = "permissions_%i" % checkPermissions
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.pref == other.pref and self.func == other.func and
|
||||
self.available == other.available)
|
||||
self.available == other.available and
|
||||
self.checkPermissions == other.checkPermissions)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
@ -1875,12 +1881,13 @@ class PropertyDefiner:
|
||||
return attr[0]
|
||||
|
||||
@staticmethod
|
||||
def getControllingCondition(interfaceMember):
|
||||
def getControllingCondition(interfaceMember, descriptor):
|
||||
return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Pref"),
|
||||
PropertyDefiner.getStringAttr(interfaceMember,
|
||||
"Func"),
|
||||
getAvailableInTestFunc(interfaceMember))
|
||||
getAvailableInTestFunc(interfaceMember),
|
||||
descriptor.checkPermissionsIndicesForMembers.get(interfaceMember.identifier.name))
|
||||
|
||||
def generatePrefableArray(self, array, name, specTemplate, specTerminator,
|
||||
specType, getCondition, getDataTuple, doIdArrays):
|
||||
@ -1912,12 +1919,12 @@ class PropertyDefiner:
|
||||
# pref control is added to members while still allowing us to define all
|
||||
# the members in the smallest number of JSAPI calls.
|
||||
assert len(array) != 0
|
||||
lastCondition = getCondition(array[0]) # So we won't put a specTerminator
|
||||
# at the very front of the list.
|
||||
lastCondition = getCondition(array[0], self.descriptor) # So we won't put a specTerminator
|
||||
# at the very front of the list.
|
||||
specs = []
|
||||
prefableSpecs = []
|
||||
|
||||
prefableTemplate = ' { true, %s, %s, &%s[%d] }'
|
||||
prefableTemplate = ' { true, %s, %s, %s, &%s[%d] }'
|
||||
prefCacheTemplate = '&%s[%d].enabled'
|
||||
|
||||
def switchToCondition(props, condition):
|
||||
@ -1931,12 +1938,13 @@ class PropertyDefiner:
|
||||
prefableSpecs.append(prefableTemplate %
|
||||
(condition.func,
|
||||
condition.available,
|
||||
condition.checkPermissions,
|
||||
name + "_specs", len(specs)))
|
||||
|
||||
switchToCondition(self, lastCondition)
|
||||
|
||||
for member in array:
|
||||
curCondition = getCondition(member)
|
||||
curCondition = getCondition(member, self.descriptor)
|
||||
if lastCondition != curCondition:
|
||||
# Terminate previous list
|
||||
specs.append(specTerminator)
|
||||
@ -2049,7 +2057,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
"methodInfo": not m.isStatic(),
|
||||
"length": methodLength(m),
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
"condition": PropertyDefiner.getControllingCondition(m),
|
||||
"condition": PropertyDefiner.getControllingCondition(m, descriptor),
|
||||
"allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"),
|
||||
"returnsPromise": m.returnsPromise()
|
||||
}
|
||||
@ -2077,7 +2085,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
"nativeName": stringifier.identifier.name,
|
||||
"length": 0,
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
"condition": PropertyDefiner.getControllingCondition(stringifier)
|
||||
"condition": PropertyDefiner.getControllingCondition(stringifier, descriptor)
|
||||
}
|
||||
if isChromeOnly(stringifier):
|
||||
self.chrome.append(toStringDesc)
|
||||
@ -2090,7 +2098,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
"nativeName": jsonifier.identifier.name,
|
||||
"length": 0,
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
"condition": PropertyDefiner.getControllingCondition(jsonifier)
|
||||
"condition": PropertyDefiner.getControllingCondition(jsonifier, descriptor)
|
||||
}
|
||||
if isChromeOnly(jsonifier):
|
||||
self.chrome.append(toJSONDesc)
|
||||
@ -2120,7 +2128,7 @@ class MethodDefiner(PropertyDefiner):
|
||||
if len(array) == 0:
|
||||
return ""
|
||||
|
||||
def condition(m):
|
||||
def condition(m, d):
|
||||
return m["condition"]
|
||||
|
||||
def specData(m):
|
||||
@ -2712,6 +2720,9 @@ class CGConstructorEnabled(CGAbstractMethod):
|
||||
availableIn = getAvailableInTestFunc(iface)
|
||||
if availableIn:
|
||||
conditions.append("%s(aCx, aObj)" % availableIn)
|
||||
checkPermissions = self.descriptor.checkPermissionsIndex
|
||||
if checkPermissions is not None:
|
||||
conditions.append("CheckPermissions(aCx, aObj, permissions_%i)" % checkPermissions)
|
||||
# We should really have some conditions
|
||||
assert len(conditions)
|
||||
return CGWrapper(CGList((CGGeneric(cond) for cond in conditions),
|
||||
@ -10268,6 +10279,15 @@ class CGDescriptor(CGThing):
|
||||
# wants a custom hook.
|
||||
cgThings.append(CGClassFinalizeHook(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))
|
||||
|
||||
properties = PropertyArrays(descriptor)
|
||||
cgThings.append(CGGeneric(define=str(properties)))
|
||||
cgThings.append(CGNativeProperties(descriptor, properties))
|
||||
|
@ -420,6 +420,34 @@ class Descriptor(DescriptorProvider):
|
||||
if '__stringifier' not in self.binaryNames:
|
||||
self.binaryNames["__stringifier"] = "Stringify"
|
||||
|
||||
|
||||
if not self.interface.isExternal():
|
||||
self.permissions = dict()
|
||||
|
||||
# Adds a permission list to this descriptor and returns the index to use.
|
||||
def addPermissions(ifaceOrMember):
|
||||
checkPermissions = ifaceOrMember.getExtendedAttribute("CheckPermissions")
|
||||
if checkPermissions is None:
|
||||
return None
|
||||
|
||||
# It's a list of whitespace-separated strings
|
||||
assert(len(checkPermissions) is 1)
|
||||
assert(checkPermissions[0] is not None)
|
||||
checkPermissions = checkPermissions[0]
|
||||
permissionsList = checkPermissions.split()
|
||||
if len(permissionsList) == 0:
|
||||
raise TypeError("Need at least one permission name for CheckPermissions")
|
||||
|
||||
permissionsList = tuple(sorted(set(permissionsList)))
|
||||
return self.permissions.setdefault(permissionsList, len(self.permissions))
|
||||
|
||||
self.checkPermissionsIndex = addPermissions(self.interface)
|
||||
self.checkPermissionsIndicesForMembers = dict()
|
||||
for m in self.interface.members:
|
||||
permissionsIndex = addPermissions(m)
|
||||
if permissionsIndex is not None:
|
||||
self.checkPermissionsIndicesForMembers[m.identifier.name] = permissionsIndex
|
||||
|
||||
# Build the prototype chain.
|
||||
self.prototypeChain = []
|
||||
parent = interface
|
||||
@ -496,7 +524,8 @@ class Descriptor(DescriptorProvider):
|
||||
return (self.interface.getExtendedAttribute("Pref") or
|
||||
self.interface.getExtendedAttribute("ChromeOnly") or
|
||||
self.interface.getExtendedAttribute("Func") or
|
||||
self.interface.getExtendedAttribute("AvailableIn"))
|
||||
self.interface.getExtendedAttribute("AvailableIn") or
|
||||
self.interface.getExtendedAttribute("CheckPermissions"))
|
||||
|
||||
def needsXrayResolveHooks(self):
|
||||
"""
|
||||
|
@ -38,6 +38,9 @@ typedef bool
|
||||
JS::Handle<JSObject*> obj,
|
||||
JS::AutoIdVector& props);
|
||||
|
||||
bool
|
||||
CheckPermissions(JSContext* aCx, JSObject* aObj, const char* const aPermissions[]);
|
||||
|
||||
struct ConstantSpec
|
||||
{
|
||||
const char* name;
|
||||
@ -52,7 +55,7 @@ struct Prefable {
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
if (!enabledFunc && !availableFunc) {
|
||||
if (!enabledFunc && !availableFunc && !checkPermissions) {
|
||||
return true;
|
||||
}
|
||||
// Just go ahead and root obj, in case enabledFunc GCs
|
||||
@ -65,6 +68,11 @@ struct Prefable {
|
||||
!availableFunc(cx, js::GetGlobalForObjectCrossCompartment(rootedObj))) {
|
||||
return false;
|
||||
}
|
||||
if (checkPermissions &&
|
||||
!CheckPermissions(cx, js::GetGlobalForObjectCrossCompartment(rootedObj),
|
||||
checkPermissions)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -79,6 +87,7 @@ struct Prefable {
|
||||
// is basically a hack to avoid having to codegen PropertyEnabled
|
||||
// implementations in case when we need to do two separate checks.
|
||||
PropertyEnabled availableFunc;
|
||||
const char* const* checkPermissions;
|
||||
// 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.
|
||||
|
@ -1001,7 +1001,8 @@ class IDLInterface(IDLObjectWithScope):
|
||||
identifier == "HeaderFile" or
|
||||
identifier == "NavigatorProperty" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "Func"):
|
||||
identifier == "Func" or
|
||||
identifier == "CheckPermissions"):
|
||||
# Known extended attributes that take a string value
|
||||
if not attr.hasValue():
|
||||
raise WebIDLError("[%s] must have a value" % identifier,
|
||||
@ -2943,7 +2944,8 @@ class IDLAttribute(IDLInterfaceMember):
|
||||
identifier == "Func" or
|
||||
identifier == "Frozen" or
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "NewObject"):
|
||||
identifier == "NewObject" or
|
||||
identifier == "CheckPermissions"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
@ -3520,7 +3522,8 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
identifier == "AvailableIn" or
|
||||
identifier == "Pure" or
|
||||
identifier == "CrossOriginCallable" or
|
||||
identifier == "WebGLHandlesContextLoss"):
|
||||
identifier == "WebGLHandlesContextLoss" or
|
||||
identifier == "CheckPermissions"):
|
||||
# Known attributes that we don't need to do anything with here
|
||||
pass
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user