mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge backout.
This commit is contained in:
commit
eada40c175
@ -1590,7 +1590,6 @@ jsval nsDOMClassInfo::sPackages_id = JSVAL_VOID;
|
||||
|
||||
static const JSClass *sObjectClass = nsnull;
|
||||
JSPropertyOp nsDOMClassInfo::sXPCNativeWrapperGetPropertyOp = nsnull;
|
||||
JSPropertyOp nsDOMClassInfo::sXrayWrapperPropertyHolderGetPropertyOp = nsnull;
|
||||
|
||||
/**
|
||||
* Set our JSClass pointer for the Object class
|
||||
@ -1850,25 +1849,6 @@ nsDOMClassInfo::ThrowJSException(JSContext *cx, nsresult aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
|
||||
|
||||
NS_PRECONDITION(!scx || !scx->IsContextInitialized() ||
|
||||
sXPCNativeWrapperGetPropertyOp,
|
||||
"Must know what the XPCNativeWrapper class GetProperty op is!");
|
||||
}
|
||||
#endif
|
||||
|
||||
JSPropertyOp op = obj->getClass()->getProperty;
|
||||
return !!op && (op == sXPCNativeWrapperGetPropertyOp ||
|
||||
op == sXrayWrapperPropertyHolderGetPropertyOp);
|
||||
}
|
||||
|
||||
nsDOMClassInfo::nsDOMClassInfo(nsDOMClassInfoData* aData) : mData(aData)
|
||||
{
|
||||
}
|
||||
|
@ -166,25 +166,37 @@ public:
|
||||
|
||||
static nsresult ThrowJSException(JSContext *cx, nsresult aResult);
|
||||
|
||||
/**
|
||||
* Get our JSClass pointer for the XPCNativeWrapper class
|
||||
*/
|
||||
static JSPropertyOp GetXPCNativeWrapperGetPropertyOp() {
|
||||
return sXPCNativeWrapperGetPropertyOp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set our JSClass pointer for the XPCNativeWrapper class
|
||||
*/
|
||||
static void SetXPCNativeWrapperGetPropertyOp(JSPropertyOp getPropertyOp) {
|
||||
NS_ASSERTION(!sXPCNativeWrapperGetPropertyOp,
|
||||
"Double set of sXPCNativeWrapperGetPropertyOp");
|
||||
sXPCNativeWrapperGetPropertyOp = getPropertyOp;
|
||||
}
|
||||
|
||||
static JSPropertyOp GetXrayWrapperPropertyHolderGetPropertyOp() {
|
||||
return sXrayWrapperPropertyHolderGetPropertyOp;
|
||||
}
|
||||
static PRBool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsIScriptContext *scx = GetScriptContextFromJSContext(cx);
|
||||
|
||||
static void SetXrayWrapperPropertyHolderGetPropertyOp(JSPropertyOp getPropertyOp) {
|
||||
sXrayWrapperPropertyHolderGetPropertyOp = getPropertyOp;
|
||||
NS_PRECONDITION(!scx || !scx->IsContextInitialized() ||
|
||||
sXPCNativeWrapperGetPropertyOp,
|
||||
"Must know what the XPCNativeWrapper class GetProperty op is!");
|
||||
}
|
||||
#endif
|
||||
|
||||
static PRBool ObjectIsNativeWrapper(JSContext* cx, JSObject* obj);
|
||||
return sXPCNativeWrapperGetPropertyOp &&
|
||||
::JS_GET_CLASS(cx, obj)->getProperty == sXPCNativeWrapperGetPropertyOp;
|
||||
}
|
||||
|
||||
static nsISupports *GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj);
|
||||
|
||||
@ -351,7 +363,6 @@ protected:
|
||||
static jsval sPackages_id;
|
||||
|
||||
static JSPropertyOp sXPCNativeWrapperGetPropertyOp;
|
||||
static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp;
|
||||
};
|
||||
|
||||
|
||||
|
@ -2631,17 +2631,12 @@ nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject)
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Now check whether we need to grab a pointer to the
|
||||
// XPCNativeWrapper and XrayWrapperPropertyHolder getProperty ops.
|
||||
// XPCNativeWrapper class
|
||||
if (!nsDOMClassInfo::GetXPCNativeWrapperGetPropertyOp()) {
|
||||
JSPropertyOp getProperty;
|
||||
xpc->GetNativeWrapperGetPropertyOp(&getProperty);
|
||||
nsDOMClassInfo::SetXPCNativeWrapperGetPropertyOp(getProperty);
|
||||
}
|
||||
if (!nsDOMClassInfo::GetXrayWrapperPropertyHolderGetPropertyOp()) {
|
||||
JSPropertyOp getProperty;
|
||||
xpc->GetXrayWrapperPropertyHolderGetPropertyOp(&getProperty);
|
||||
nsDOMClassInfo::SetXrayWrapperPropertyHolderGetPropertyOp(getProperty);
|
||||
}
|
||||
} else {
|
||||
// There's already a global object. We are preparing this outer window
|
||||
// object for use as a real outer window (i.e. everything needs to live on
|
||||
|
@ -2085,7 +2085,7 @@ private:
|
||||
* threshold when p is not null. The function takes the pointer and not
|
||||
* a boolean flag to minimize the amount of code in its inlined callers.
|
||||
*/
|
||||
JS_FRIEND_API(void) checkMallocGCPressure(void *p);
|
||||
void checkMallocGCPressure(void *p);
|
||||
};
|
||||
|
||||
JS_ALWAYS_INLINE JSObject *
|
||||
@ -2806,7 +2806,7 @@ js_ReportOutOfScriptQuota(JSContext *cx);
|
||||
extern void
|
||||
js_ReportOverRecursed(JSContext *cx);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
extern void
|
||||
js_ReportAllocationOverflow(JSContext *cx);
|
||||
|
||||
#define JS_CHECK_RECURSION(cx, onerror) \
|
||||
|
@ -698,7 +698,7 @@ struct JSObject {
|
||||
|
||||
inline void dropProperty(JSContext *cx, JSProperty *prop);
|
||||
|
||||
JS_FRIEND_API(JSCompartment *) getCompartment(JSContext *cx);
|
||||
JSCompartment *getCompartment(JSContext *cx);
|
||||
|
||||
void swap(JSObject *obj);
|
||||
|
||||
@ -721,8 +721,10 @@ struct JSObject {
|
||||
inline bool isObjectProxy() const;
|
||||
inline bool isFunctionProxy() const;
|
||||
|
||||
JS_FRIEND_API(bool) isWrapper() const;
|
||||
JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL);
|
||||
bool isWrapper() const;
|
||||
JSObject *unwrap();
|
||||
|
||||
bool isCrossCompartmentWrapper() const;
|
||||
|
||||
inline bool unbrand(JSContext *cx);
|
||||
};
|
||||
|
@ -68,21 +68,21 @@ class JSProxyHandler {
|
||||
virtual bool fix(JSContext *cx, JSObject *proxy, jsval *vp) = 0;
|
||||
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp);
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
uintN argc, jsval *argv, jsval *rval);
|
||||
virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *proxy);
|
||||
virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
|
||||
virtual JS_FRIEND_API(void) finalize(JSContext *cx, JSObject *proxy);
|
||||
virtual JS_FRIEND_API(void) trace(JSTracer *trc, JSObject *proxy);
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *proxy);
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
|
||||
virtual void finalize(JSContext *cx, JSObject *proxy);
|
||||
virtual void trace(JSTracer *trc, JSObject *proxy);
|
||||
|
||||
inline void *family() {
|
||||
return mFamily;
|
||||
|
@ -582,7 +582,7 @@ typedef JSBool
|
||||
* destination compartment.
|
||||
*/
|
||||
typedef JSObject *
|
||||
(* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, uintN flags);
|
||||
(* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
|
@ -59,20 +59,15 @@ JSObject::isWrapper() const
|
||||
}
|
||||
|
||||
JSObject *
|
||||
JSObject::unwrap(uintN *flagsp)
|
||||
JSObject::unwrap()
|
||||
{
|
||||
JSObject *wrapped = this;
|
||||
uintN flags = 0;
|
||||
if (wrapped->isWrapper()) {
|
||||
flags |= static_cast<JSWrapper *>(wrapped->getProxyHandler())->flags();
|
||||
while (wrapped->isWrapper())
|
||||
wrapped = JSVAL_TO_OBJECT(wrapped->getProxyPrivate());
|
||||
}
|
||||
if (flagsp)
|
||||
*flagsp = flags;
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
JSWrapper::JSWrapper(uintN flags) : JSProxyHandler(&sWrapperFamily), mFlags(flags)
|
||||
JSWrapper::JSWrapper(void *kind) : JSProxyHandler(&sWrapperFamily), mKind(kind)
|
||||
{
|
||||
}
|
||||
|
||||
@ -80,195 +75,116 @@ JSWrapper::~JSWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
#define CHECKED(op, set) \
|
||||
JS_BEGIN_MACRO \
|
||||
if (!enter(cx, wrapper, id, set)) \
|
||||
return false; \
|
||||
bool ok = (op); \
|
||||
leave(cx, wrapper); \
|
||||
return ok; \
|
||||
JS_END_MACRO
|
||||
|
||||
#define SET(action) CHECKED(action, true)
|
||||
#define GET(action) CHECKED(action, false)
|
||||
|
||||
bool
|
||||
JSWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
JSWrapper::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc)
|
||||
{
|
||||
GET(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc));
|
||||
JSObject *wobj = wrappedObject(proxy);
|
||||
return JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, desc);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSPropertyDescriptor *desc)
|
||||
bool
|
||||
JSWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc)
|
||||
{
|
||||
if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
|
||||
return JS_GetPropertyDescriptorById(cx, wrappedObject(proxy), id, JSRESOLVE_QUALIFIED, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc)
|
||||
{
|
||||
return JS_DefinePropertyById(cx, wrappedObject(proxy), id, desc->value,
|
||||
desc->getter, desc->setter, desc->attrs);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
return GetPropertyNames(cx, wrappedObject(proxy), JSITER_OWNONLY | JSITER_HIDDEN, props);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
AutoValueRooter tvr(cx);
|
||||
if (!JS_DeletePropertyById2(cx, wrappedObject(proxy), id, tvr.addr()))
|
||||
return false;
|
||||
if (desc->obj != obj)
|
||||
desc->obj = NULL;
|
||||
*bp = js_ValueToBoolean(tvr.value());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
JSPropertyDescriptor *desc)
|
||||
JSWrapper::enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
GET(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc));
|
||||
return GetPropertyNames(cx, wrappedObject(proxy), 0, props);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
JSPropertyDescriptor *desc)
|
||||
{
|
||||
SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, desc->value,
|
||||
desc->getter, desc->setter, desc->attrs));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
static jsid id = JSVAL_VOID;
|
||||
GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, props));
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueToBoolean(jsval *vp, bool *bp)
|
||||
{
|
||||
*bp = js_ValueToBoolean(*vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
jsval v;
|
||||
SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, &v) &&
|
||||
ValueToBoolean(&v, bp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
static jsid id = JSVAL_VOID;
|
||||
GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, props));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::fix(JSContext *cx, JSObject *wrapper, jsval *vp)
|
||||
JSWrapper::fix(JSContext *cx, JSObject *proxy, jsval *vp)
|
||||
{
|
||||
*vp = JSVAL_VOID;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
Cond(JSBool b, bool *bp)
|
||||
{
|
||||
*bp = !!b;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
JSWrapper::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
JSBool found;
|
||||
GET(JS_HasPropertyById(cx, wrappedObject(wrapper), id, &found) &&
|
||||
Cond(found, bp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
JSPropertyDescriptor desc;
|
||||
JSObject *wobj = wrappedObject(wrapper);
|
||||
GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, &desc) &&
|
||||
Cond(desc.obj == wobj, bp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
GET(JS_GetPropertyById(cx, wrappedObject(wrapper), id, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
SET(JS_SetPropertyById(cx, wrappedObject(wrapper), id, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
const jsid id = JSVAL_VOID;
|
||||
GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, props));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp)
|
||||
{
|
||||
const jsid id = JSVAL_VOID;
|
||||
GET(GetIterator(cx, wrappedObject(wrapper), flags, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp)
|
||||
{
|
||||
const jsid id = JSVAL_VOID;
|
||||
GET(JSProxyHandler::call(cx, wrapper, argc, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::construct(JSContext *cx, JSObject *wrapper, JSObject *receiver,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
const jsid id = JSVAL_VOID;
|
||||
GET(JSProxyHandler::construct(cx, wrapper, receiver, argc, argv, rval));
|
||||
}
|
||||
|
||||
JSString *
|
||||
JSWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
|
||||
{
|
||||
JSString *str;
|
||||
if (!enter(cx, wrapper, JSVAL_VOID, false))
|
||||
return NULL;
|
||||
str = JSProxyHandler::obj_toString(cx, wrapper);
|
||||
leave(cx, wrapper);
|
||||
return str;
|
||||
}
|
||||
|
||||
JSString *
|
||||
JSWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
|
||||
{
|
||||
JSString *str;
|
||||
if (!enter(cx, wrapper, JSVAL_VOID, false))
|
||||
return NULL;
|
||||
str = JSProxyHandler::fun_toString(cx, wrapper, indent);
|
||||
leave(cx, wrapper);
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
JSWrapper::trace(JSTracer *trc, JSObject *wrapper)
|
||||
{
|
||||
JS_CALL_OBJECT_TRACER(trc, wrappedObject(wrapper), "wrappedObject");
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::enter(JSContext *cx, JSObject *wrapper, jsval id, bool set)
|
||||
{
|
||||
if (!JS_HasPropertyById(cx, wrappedObject(proxy), id, &found))
|
||||
return false;
|
||||
*bp = !!found;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSWrapper::leave(JSContext *cx, JSObject *wrapper)
|
||||
bool
|
||||
JSWrapper::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
JSPropertyDescriptor desc;
|
||||
JSObject *wobj = wrappedObject(proxy);
|
||||
if (!JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, &desc))
|
||||
return false;
|
||||
*bp = (desc.obj == wobj);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSWrapper JSWrapper::singleton(0);
|
||||
bool
|
||||
JSWrapper::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
return JS_GetPropertyById(cx, wrappedObject(proxy), id, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
return JS_SetPropertyById(cx, wrappedObject(proxy), id, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
return GetPropertyNames(cx, wrappedObject(proxy), JSITER_OWNONLY, props);
|
||||
}
|
||||
|
||||
bool
|
||||
JSWrapper::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp)
|
||||
{
|
||||
return GetIterator(cx, wrappedObject(proxy), flags, vp);
|
||||
}
|
||||
|
||||
void
|
||||
JSWrapper::trace(JSTracer *trc, JSObject *proxy)
|
||||
{
|
||||
JS_CALL_OBJECT_TRACER(trc, wrappedObject(proxy), "wrappedObject");
|
||||
}
|
||||
|
||||
static int sTransparentWrapperKind;
|
||||
|
||||
JSWrapper JSWrapper::singleton(&sTransparentWrapperKind);
|
||||
|
||||
JSObject *
|
||||
JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
|
||||
JSWrapper *handler)
|
||||
JSProxyHandler *handler)
|
||||
{
|
||||
return NewProxyObject(cx, handler, OBJECT_TO_JSVAL(obj), proto, parent,
|
||||
obj->isCallable() ? obj : NULL, NULL);
|
||||
@ -279,9 +195,8 @@ JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
|
||||
namespace js {
|
||||
|
||||
extern JSObject *
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, uintN flags)
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto)
|
||||
{
|
||||
JS_ASSERT(!obj->isWrapper());
|
||||
return JSWrapper::New(cx, obj, wrappedProto, NULL, &JSCrossCompartmentWrapper::singleton);
|
||||
}
|
||||
|
||||
@ -307,8 +222,6 @@ JSCompartment::wrap(JSContext *cx, jsval *vp)
|
||||
{
|
||||
JS_ASSERT(cx->compartment == this);
|
||||
|
||||
uintN flags = 0;
|
||||
|
||||
JS_CHECK_RECURSION(cx, return false);
|
||||
|
||||
/* Only GC things have to be wrapped or copied. */
|
||||
@ -325,7 +238,7 @@ JSCompartment::wrap(JSContext *cx, jsval *vp)
|
||||
|
||||
/* Unwrap incoming objects. */
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp)) {
|
||||
JSObject *obj = JSVAL_TO_OBJECT(*vp)->unwrap(&flags);
|
||||
JSObject *obj = JSVAL_TO_OBJECT(*vp)->unwrap();
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
/* If the wrapped object is already in this compartment, we are done. */
|
||||
if (obj->getCompartment(cx) == this)
|
||||
@ -358,19 +271,14 @@ JSCompartment::wrap(JSContext *cx, jsval *vp)
|
||||
* here (since Object.prototype->parent->proto leads to Object.prototype
|
||||
* itself).
|
||||
*/
|
||||
JSObject *proto = obj->getProto();
|
||||
if (!wrap(cx, &proto))
|
||||
AutoObjectRooter proto(cx, obj->getProto());
|
||||
if (!wrap(cx, proto.addr()))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* We hand in the original wrapped object into the wrap hook to allow
|
||||
* the wrap hook to reason over what wrappers are currently applied
|
||||
* to the object.
|
||||
*/
|
||||
JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, flags);
|
||||
JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto.object());
|
||||
if (!wrapper)
|
||||
return false;
|
||||
wrapper->setProto(proto);
|
||||
wrapper->setProto(proto.object());
|
||||
*vp = OBJECT_TO_JSVAL(wrapper);
|
||||
if (!crossCompartmentWrappers.put(wrapper->getProxyPrivate(), *vp))
|
||||
return false;
|
||||
@ -547,7 +455,16 @@ AutoCompartment::leave()
|
||||
|
||||
/* Cross compartment wrappers. */
|
||||
|
||||
JSCrossCompartmentWrapper::JSCrossCompartmentWrapper(uintN flags) : JSWrapper(flags)
|
||||
static int sCrossCompartmentWrapperKind = 0;
|
||||
|
||||
bool
|
||||
JSObject::isCrossCompartmentWrapper() const
|
||||
{
|
||||
return isWrapper() &&
|
||||
static_cast<JSWrapper *>(getProxyHandler())->kind() == &sCrossCompartmentWrapperKind;
|
||||
}
|
||||
|
||||
JSCrossCompartmentWrapper::JSCrossCompartmentWrapper() : JSWrapper(&sCrossCompartmentWrapperKind)
|
||||
{
|
||||
}
|
||||
|
||||
@ -555,122 +472,116 @@ JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::isCrossCompartmentWrapper(JSObject *obj)
|
||||
{
|
||||
return obj->getProxyHandler() == &JSCrossCompartmentWrapper::singleton;
|
||||
}
|
||||
|
||||
#define PIERCE(cx, wrapper, mode, pre, op, post) \
|
||||
#define PIERCE(cx, proxy, mode, pre, op, post) \
|
||||
JS_BEGIN_MACRO \
|
||||
AutoCompartment call(cx, wrappedObject(wrapper)); \
|
||||
if (!call.enter()) \
|
||||
AutoCompartment call(cx, wrappedObject(proxy)); \
|
||||
if (!call.enter() || !(pre) || !enter(cx, proxy, id, mode) || !(op)) \
|
||||
return false; \
|
||||
bool ok = (pre) && (op); \
|
||||
leave(cx, proxy); \
|
||||
call.leave(); \
|
||||
return ok && (post); \
|
||||
return (post); \
|
||||
JS_END_MACRO
|
||||
|
||||
#define NOTHING (true)
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc)
|
||||
JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
call.destination->wrapId(cx, &id),
|
||||
JSWrapper::getPropertyDescriptor(cx, wrapper, id, desc),
|
||||
JSWrapper::getPropertyDescriptor(cx, proxy, id, desc),
|
||||
call.origin->wrap(cx, desc));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc)
|
||||
JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
call.destination->wrapId(cx, &id),
|
||||
JSWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc),
|
||||
JSWrapper::getOwnPropertyDescriptor(cx, proxy, id, desc),
|
||||
call.origin->wrap(cx, desc));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc)
|
||||
JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
|
||||
{
|
||||
AutoDescriptor desc2(cx, desc);
|
||||
PIERCE(cx, wrapper, SET,
|
||||
PIERCE(cx, proxy, SET,
|
||||
call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2),
|
||||
JSWrapper::defineProperty(cx, wrapper, id, &desc2),
|
||||
JSWrapper::getOwnPropertyDescriptor(cx, proxy, id, &desc2),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
NOTHING,
|
||||
JSWrapper::getOwnPropertyNames(cx, wrapper, props),
|
||||
JSWrapper::getOwnPropertyNames(cx, proxy, props),
|
||||
call.origin->wrap(cx, props));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
PIERCE(cx, wrapper, SET,
|
||||
PIERCE(cx, proxy, SET,
|
||||
call.destination->wrapId(cx, &id),
|
||||
JSWrapper::delete_(cx, wrapper, id, bp),
|
||||
JSWrapper::delete_(cx, proxy, id, bp),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
NOTHING,
|
||||
JSWrapper::enumerate(cx, wrapper, props),
|
||||
JSWrapper::enumerate(cx, proxy, props),
|
||||
call.origin->wrap(cx, props));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
call.destination->wrapId(cx, &id),
|
||||
JSWrapper::has(cx, wrapper, id, bp),
|
||||
JSWrapper::has(cx, proxy, id, bp),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
call.destination->wrapId(cx, &id),
|
||||
JSWrapper::hasOwn(cx, wrapper, id, bp),
|
||||
JSWrapper::hasOwn(cx, proxy, id, bp),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp)
|
||||
JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id),
|
||||
JSWrapper::get(cx, wrapper, receiver, id, vp),
|
||||
JSWrapper::get(cx, proxy, receiver, id, vp),
|
||||
call.origin->wrap(cx, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp)
|
||||
JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp)
|
||||
{
|
||||
AutoValueRooter tvr(cx, *vp);
|
||||
PIERCE(cx, wrapper, SET,
|
||||
PIERCE(cx, proxy, SET,
|
||||
call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id) && call.destination->wrap(cx, tvr.addr()),
|
||||
JSWrapper::set(cx, wrapper, receiver, id, tvr.addr()),
|
||||
JSWrapper::set(cx, proxy, receiver, id, tvr.addr()),
|
||||
NOTHING);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
NOTHING,
|
||||
JSWrapper::enumerateOwn(cx, wrapper, props),
|
||||
JSWrapper::enumerateOwn(cx, proxy, props),
|
||||
call.origin->wrap(cx, props));
|
||||
}
|
||||
|
||||
@ -707,18 +618,18 @@ Reify(JSContext *cx, JSCompartment *origin, jsval *vp)
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp)
|
||||
JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp)
|
||||
{
|
||||
PIERCE(cx, wrapper, GET,
|
||||
PIERCE(cx, proxy, GET,
|
||||
NOTHING,
|
||||
JSWrapper::iterate(cx, wrapper, flags, vp),
|
||||
JSWrapper::iterate(cx, proxy, flags, vp),
|
||||
CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp));
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp)
|
||||
JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp)
|
||||
{
|
||||
AutoCompartment call(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrappedObject(proxy));
|
||||
if (!call.enter())
|
||||
return false;
|
||||
|
||||
@ -733,18 +644,19 @@ JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, js
|
||||
jsval *fakevp = call.getvp();
|
||||
fakevp[0] = vp[0];
|
||||
fakevp[1] = vp[1];
|
||||
if (!JSWrapper::call(cx, wrapper, argc, vp))
|
||||
if (!enter(cx, proxy, JSVAL_VOID, GET) || !JSWrapper::call(cx, proxy, argc, vp))
|
||||
return false;
|
||||
|
||||
leave(cx, proxy);
|
||||
call.leave();
|
||||
return call.origin->wrap(cx, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, JSObject *receiver,
|
||||
JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
AutoCompartment call(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrappedObject(proxy));
|
||||
if (!call.enter())
|
||||
return false;
|
||||
|
||||
@ -755,26 +667,32 @@ JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, JSObject
|
||||
jsval *vp = call.getvp();
|
||||
vp[0] = OBJECT_TO_JSVAL(call.target);
|
||||
if (!call.destination->wrap(cx, &receiver) ||
|
||||
!JSWrapper::construct(cx, wrapper, receiver, argc, argv, rval)) {
|
||||
!enter(cx, proxy, JSVAL_VOID, GET) ||
|
||||
!JSWrapper::construct(cx, proxy, receiver, argc, argv, rval)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
leave(cx, proxy);
|
||||
call.leave();
|
||||
return call.origin->wrap(cx, rval) &&
|
||||
call.origin->wrapException(cx);
|
||||
}
|
||||
|
||||
JSString *
|
||||
JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
|
||||
JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
AutoCompartment call(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrappedObject(proxy));
|
||||
if (!call.enter())
|
||||
return NULL;
|
||||
|
||||
JSString *str = JSWrapper::obj_toString(cx, wrapper);
|
||||
if (!enter(cx, proxy, JSVAL_VOID, GET))
|
||||
return NULL;
|
||||
JSString *str = JSWrapper::obj_toString(cx, proxy);
|
||||
if (!str)
|
||||
return NULL;
|
||||
AutoValueRooter tvr(cx, str);
|
||||
|
||||
leave(cx, proxy);
|
||||
call.leave();
|
||||
if (!call.origin->wrap(cx, &str))
|
||||
return NULL;
|
||||
@ -782,20 +700,35 @@ JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
|
||||
}
|
||||
|
||||
JSString *
|
||||
JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
|
||||
JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *proxy, uintN indent)
|
||||
{
|
||||
AutoCompartment call(cx, wrappedObject(wrapper));
|
||||
AutoCompartment call(cx, wrappedObject(proxy));
|
||||
if (!call.enter())
|
||||
return NULL;
|
||||
|
||||
JSString *str = JSWrapper::fun_toString(cx, wrapper, indent);
|
||||
if (!enter(cx, proxy, JSVAL_VOID, GET))
|
||||
return NULL;
|
||||
JSString *str = JSWrapper::fun_toString(cx, proxy, indent);
|
||||
if (!str)
|
||||
return NULL;
|
||||
AutoValueRooter tvr(cx, str);
|
||||
|
||||
leave(cx, proxy);
|
||||
call.leave();
|
||||
if (!call.origin->wrap(cx, &str))
|
||||
return NULL;
|
||||
return str;
|
||||
}
|
||||
|
||||
JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton(0);
|
||||
bool
|
||||
JSCrossCompartmentWrapper::enter(JSContext *cx, JSObject *proxy, jsval id, Mode mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSCrossCompartmentWrapper::leave(JSContext *cx, JSObject *proxy)
|
||||
{
|
||||
}
|
||||
|
||||
JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton;
|
||||
|
@ -47,99 +47,95 @@
|
||||
|
||||
/* No-op wrapper handler base class. */
|
||||
class JSWrapper : public js::JSProxyHandler {
|
||||
uintN mFlags;
|
||||
void *mKind;
|
||||
protected:
|
||||
explicit JS_FRIEND_API(JSWrapper(void *kind));
|
||||
|
||||
public:
|
||||
uintN flags() const { return mFlags; }
|
||||
|
||||
explicit JS_FRIEND_API(JSWrapper(uintN flags));
|
||||
|
||||
typedef enum { PermitObjectAccess, PermitPropertyAccess, DenyAccess } Permission;
|
||||
|
||||
JS_FRIEND_API(virtual ~JSWrapper());
|
||||
|
||||
/* ES5 Harmony fundamental wrapper traps. */
|
||||
virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *wrapper,
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *proxy,
|
||||
js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *wrapper, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *proxy, jsval *vp);
|
||||
|
||||
/* ES5 Harmony derived wrapper traps. */
|
||||
virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id,
|
||||
jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id,
|
||||
virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id,
|
||||
jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *wrapper, JSObject *receiver,
|
||||
uintN argc, jsval *argv, jsval *rval);
|
||||
virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *wrapper);
|
||||
virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
|
||||
|
||||
virtual JS_FRIEND_API(void) trace(JSTracer *trc, JSObject *wrapper);
|
||||
|
||||
/* Policy enforcement traps. */
|
||||
virtual JS_FRIEND_API(bool) enter(JSContext *cx, JSObject *wrapper, jsid id, bool set);
|
||||
virtual JS_FRIEND_API(void) leave(JSContext *cx, JSObject *wrapper);
|
||||
virtual JS_FRIEND_API(void) trace(JSTracer *trc, JSObject *proxy);
|
||||
|
||||
static JS_FRIEND_API(JSWrapper) singleton;
|
||||
|
||||
static JS_FRIEND_API(JSObject *) New(JSContext *cx, JSObject *obj,
|
||||
JSObject *proto, JSObject *parent,
|
||||
JSWrapper *handler);
|
||||
JSProxyHandler *handler);
|
||||
|
||||
static inline JSObject *wrappedObject(JSObject *wrapper) {
|
||||
return JSVAL_TO_OBJECT(wrapper->getProxyPrivate());
|
||||
inline void *kind() {
|
||||
return mKind;
|
||||
}
|
||||
|
||||
static inline JSObject *wrappedObject(JSObject *proxy) {
|
||||
return JSVAL_TO_OBJECT(proxy->getProxyPrivate());
|
||||
}
|
||||
};
|
||||
|
||||
/* Base class for all cross compartment wrapper handlers. */
|
||||
class JSCrossCompartmentWrapper : public JSWrapper {
|
||||
protected:
|
||||
JS_FRIEND_API(JSCrossCompartmentWrapper());
|
||||
|
||||
public:
|
||||
JS_FRIEND_API(JSCrossCompartmentWrapper(uintN flags));
|
||||
typedef enum { GET, SET } Mode;
|
||||
|
||||
virtual JS_FRIEND_API(~JSCrossCompartmentWrapper());
|
||||
|
||||
/* ES5 Harmony fundamental wrapper traps. */
|
||||
virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
/* ES5 Harmony fundamental proxy traps. */
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual bool enumerate(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
|
||||
/* ES5 Harmony derived wrapper traps. */
|
||||
virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp);
|
||||
/* ES5 Harmony derived proxy traps. */
|
||||
virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
|
||||
virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp);
|
||||
virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props);
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp);
|
||||
virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *wrapper, JSObject *receiver,
|
||||
virtual bool call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp);
|
||||
virtual bool construct(JSContext *cx, JSObject *proxy, JSObject *receiver,
|
||||
uintN argc, jsval *argv, jsval *rval);
|
||||
virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *wrapper);
|
||||
virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
|
||||
virtual JSString *obj_toString(JSContext *cx, JSObject *proxy);
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent);
|
||||
|
||||
static JS_FRIEND_API(bool) isCrossCompartmentWrapper(JSObject *obj);
|
||||
/* Policy enforcement traps. */
|
||||
virtual bool enter(JSContext *cx, JSObject *proxy, jsid id, Mode mode);
|
||||
virtual void leave(JSContext *cx, JSObject *proxy);
|
||||
|
||||
static JS_FRIEND_API(JSCrossCompartmentWrapper) singleton;
|
||||
static JSCrossCompartmentWrapper singleton;
|
||||
|
||||
/* Default id used for filter when the trap signature does not contain an id. */
|
||||
static const jsid id = JSVAL_VOID;
|
||||
@ -180,7 +176,7 @@ class AutoCompartment
|
||||
};
|
||||
|
||||
extern JSObject *
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, uintN flags);
|
||||
TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto);
|
||||
|
||||
}
|
||||
|
||||
|
@ -2998,7 +2998,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
||||
JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
|
||||
{
|
||||
JSAutoCrossCompartmentCall ac;
|
||||
if (JSCrossCompartmentWrapper::isCrossCompartmentWrapper(sobj)) {
|
||||
if (sobj->isCrossCompartmentWrapper()) {
|
||||
sobj = sobj->unwrap();
|
||||
if (!ac.enter(cx, sobj))
|
||||
return false;
|
||||
|
@ -397,7 +397,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
|
||||
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
|
||||
%}
|
||||
|
||||
[uuid(c53c54ac-afc1-458a-98f5-cadb52574e40)]
|
||||
[uuid(0332b12a-8103-4601-aed3-b9933a0d9441)]
|
||||
interface nsIXPConnect : nsISupports
|
||||
{
|
||||
%{ C++
|
||||
@ -871,5 +871,4 @@ interface nsIXPConnect : nsISupports
|
||||
%}
|
||||
|
||||
[notxpcom] void getNativeWrapperGetPropertyOp(out JSPropertyOp getProperty);
|
||||
[notxpcom] void getXrayWrapperPropertyHolderGetPropertyOp(out JSPropertyOp getProperty);
|
||||
};
|
||||
|
@ -134,16 +134,14 @@ EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
LIBS = wrappers/$(LIB_PREFIX)wrappers.$(LIB_SUFFIX)
|
||||
|
||||
ifdef MOZ_JSLOADER
|
||||
SHARED_LIBRARY_LIBS = \
|
||||
../loader/$(LIB_PREFIX)jsloader_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
./wrappers/$(LIB_PREFIX)xpcwrappers_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
DEFINES += \
|
||||
|
@ -56,8 +56,6 @@
|
||||
|
||||
#include "jstypedarray.h"
|
||||
|
||||
#include "wrappers/XrayWrapper.h"
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS6(nsXPConnect,
|
||||
nsIXPConnect,
|
||||
nsISupportsWeakReference,
|
||||
@ -2592,7 +2590,7 @@ nsXPConnect::GetWrapperForObject(JSContext* aJSContext,
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*_retval = OBJECT_TO_JSVAL(wrappedObj);
|
||||
if(wrapper && wrapper->NeedsSOW() &&
|
||||
if(wrapper && wrapper->NeedsChromeWrapper() &&
|
||||
!SystemOnlyWrapper::WrapObject(aJSContext, aScope, *_retval, _retval))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
@ -2795,12 +2793,6 @@ nsXPConnect::GetPrincipal(JSObject* obj, PRBool allowShortCircuit) const
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsXPConnect::GetXrayWrapperPropertyHolderGetPropertyOp(JSPropertyOp *getPropertyPtr)
|
||||
{
|
||||
*getPropertyPtr = xpc::HolderClass.getProperty;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
nsXPConnect::GetNativeWrapperGetPropertyOp(JSPropertyOp *getPropertyPtr)
|
||||
{
|
||||
|
@ -37,205 +37,40 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "AccessCheck.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDOMWindowCollection.h"
|
||||
#include "jsapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
#include "XPCWrapper.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
#include "AccessCheck.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
static nsIPrincipal *
|
||||
nsIPrincipal *
|
||||
GetCompartmentPrincipal(JSCompartment *compartment)
|
||||
{
|
||||
return static_cast<nsJSPrincipals *>(compartment->principals)->nsIPrincipalPtr;
|
||||
}
|
||||
|
||||
bool
|
||||
AccessCheck::isSameOrigin(JSCompartment *a, JSCompartment *b)
|
||||
{
|
||||
PRBool cond;
|
||||
return NS_SUCCEEDED(GetCompartmentPrincipal(a)->Equals(GetCompartmentPrincipal(b), &cond)) &&
|
||||
cond;
|
||||
}
|
||||
|
||||
bool
|
||||
AccessCheck::isChrome(JSCompartment *compartment)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PRBool privileged;
|
||||
nsIPrincipal *principal = GetCompartmentPrincipal(compartment);
|
||||
return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged;
|
||||
}
|
||||
|
||||
#define NAME(ch, str, cases) case ch: if (!strcmp(name, str)) switch (prop[0]) { cases }; break;
|
||||
#define PROP(ch, actions) case ch: { actions }; break;
|
||||
#define RW(str) if (!strcmp(prop, str)) return true;
|
||||
#define R(str) if (!set && !strcmp(prop, str)) return true;
|
||||
#define W(str) if (set && !strcmp(prop, str)) return true;
|
||||
|
||||
// Hardcoded policy for cross origin property access. This was culled from the
|
||||
// preferences file (all.js). We don't want users to overwrite highly sensitive
|
||||
// security policies.
|
||||
static bool
|
||||
IsPermitted(const char *name, const char* prop, bool set)
|
||||
{
|
||||
switch(name[0]) {
|
||||
NAME('D', "DOMException",
|
||||
PROP('c', RW("code"))
|
||||
PROP('m', RW("message"))
|
||||
PROP('n', RW("name"))
|
||||
PROP('r', RW("result")))
|
||||
NAME('H', "History",
|
||||
PROP('b', R("back"))
|
||||
PROP('f', R("forward"))
|
||||
PROP('g', R("go")))
|
||||
NAME('N', "Navigator",
|
||||
PROP('p', RW("preference")))
|
||||
NAME('W', "Window",
|
||||
PROP('b', R("blur"))
|
||||
PROP('c', R("close") R("closed"))
|
||||
PROP('f', R("focus") R("frames"))
|
||||
PROP('h', R("history"))
|
||||
PROP('l', RW("location") R("length"))
|
||||
PROP('o', R("opener"))
|
||||
PROP('p', R("parent") R("postMessage"))
|
||||
PROP('s', R("self"))
|
||||
PROP('t', R("top"))
|
||||
PROP('w', R("window")))
|
||||
NAME('X', "XMLHttpRequest",
|
||||
PROP('o', RW("open-uri")))
|
||||
NAME('S', "SOAPCall",
|
||||
PROP('i', RW("invokeVerifySourceHeader")))
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef NAME
|
||||
#undef RW
|
||||
#undef R
|
||||
#undef W
|
||||
|
||||
static bool
|
||||
IsFrameId(JSObject *obj, jsid id)
|
||||
{
|
||||
XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(obj->getPrivate());
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domwin(do_QueryWrappedNative(wn));
|
||||
if (!domwin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMWindowCollection> col;
|
||||
domwin->GetFrames(getter_AddRefs(col));
|
||||
if (!col) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JSID_IS_INT(id)) {
|
||||
col->Item(JSID_TO_INT(id), getter_AddRefs(domwin));
|
||||
} else if (JSID_IS_ATOM(id)) {
|
||||
nsAutoString str(reinterpret_cast<PRUnichar *>
|
||||
(JS_GetStringChars(ATOM_TO_STRING(JSID_TO_ATOM(id)))));
|
||||
col->NamedItem(str, getter_AddRefs(domwin));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return domwin != nsnull;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsWindow(const char *name)
|
||||
{
|
||||
return name[0] == 'W' && !strcmp(name, "Window");
|
||||
}
|
||||
|
||||
bool
|
||||
AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapper, jsid id, bool set)
|
||||
{
|
||||
JSObject *obj = JSWrapper::wrappedObject(wrapper);
|
||||
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *name = obj->getClass()->name;
|
||||
|
||||
if (JSID_IS_ATOM(id)) {
|
||||
JSString *str = ATOM_TO_STRING(JSID_TO_ATOM(id));
|
||||
const char *prop = JS_GetStringBytes(str);
|
||||
if (IsPermitted(name, prop, set))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsWindow(name) && IsFrameId(obj, id))
|
||||
return true;
|
||||
|
||||
PRBool privileged;
|
||||
return NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged;
|
||||
}
|
||||
|
||||
bool
|
||||
AccessCheck::isSystemOnlyAccessPermitted(JSContext *cx)
|
||||
AccessCheck::isPrivileged(JSCompartment *compartment)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if(!ssm) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JSStackFrame *fp;
|
||||
nsIPrincipal *principal = ssm->GetCxSubjectPrincipalAndFrame(cx, &fp);
|
||||
if (!principal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fp) {
|
||||
if (!JS_FrameIterator(cx, &fp)) {
|
||||
// No code at all is running. So we must be arriving here as the result
|
||||
// of C++ code asking us to do something. Allow access.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Some code is running, we can't make the assumption, as above, but we
|
||||
// can't use a native frame, so clear fp.
|
||||
fp = NULL;
|
||||
} else if (!fp->script) {
|
||||
fp = NULL;
|
||||
}
|
||||
|
||||
PRBool privileged;
|
||||
if (NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) &&
|
||||
privileged) {
|
||||
if(NS_SUCCEEDED(ssm->IsSystemPrincipal(GetCompartmentPrincipal(compartment), &privileged))
|
||||
&& privileged) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allow any code loaded from chrome://global/ to touch us, even if it was
|
||||
// cloned into a less privileged context.
|
||||
static const char prefix[] = "chrome://global/";
|
||||
const char *filename;
|
||||
if (fp &&
|
||||
(filename = fp->script->filename) &&
|
||||
!strncmp(filename, prefix, NS_ARRAY_LENGTH(prefix) - 1)) {
|
||||
if(NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return NS_SUCCEEDED(ssm->IsCapabilityEnabled("UniversalXPConnect", &privileged)) && privileged;
|
||||
}
|
||||
|
||||
bool
|
||||
AccessCheck::needsSystemOnlyWrapper(JSObject *obj)
|
||||
{
|
||||
NS_ASSERTION(IS_WN_WRAPPER_OBJECT(obj), "expected a wrapped native here");
|
||||
XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(obj->getPrivate());
|
||||
return wn->NeedsSOW();
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -249,97 +84,32 @@ AccessCheck::deny(JSContext *cx, jsid id)
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 } Access;
|
||||
|
||||
bool
|
||||
ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm)
|
||||
AccessCheck::enter(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject, jsid id,
|
||||
JSCrossCompartmentWrapper::Mode mode)
|
||||
{
|
||||
JSObject *holder = JSWrapper::wrappedObject(wrapper);
|
||||
|
||||
perm = DenyAccess;
|
||||
|
||||
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
|
||||
|
||||
JSBool found = JS_FALSE;
|
||||
if (!JS_HasPropertyById(cx, holder, exposedPropsId, &found))
|
||||
return false;
|
||||
if (!found) {
|
||||
perm = PermitObjectAccess;
|
||||
return true; // Allow
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if(!ssm) {
|
||||
return true;
|
||||
}
|
||||
JSStackFrame *fp = NULL;
|
||||
nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp),
|
||||
GetCompartmentPrincipal(wrappedObject->getCompartment(cx)));
|
||||
if(NS_FAILED(rv)) {
|
||||
NS_WARNING("Not allowing call because we're out of memory");
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id == JSVAL_VOID) {
|
||||
// This will force the caller to call us back for individual property accesses.
|
||||
perm = PermitPropertyAccess;
|
||||
return true;
|
||||
}
|
||||
|
||||
jsval exposedProps;
|
||||
if (!JS_LookupPropertyById(cx, holder, exposedPropsId, &exposedProps))
|
||||
return false;
|
||||
|
||||
if (JSVAL_IS_VOID(exposedProps) || JSVAL_IS_NULL(exposedProps)) {
|
||||
return true; // Deny
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_OBJECT(exposedProps)) {
|
||||
JS_ReportError(cx, "__exposedProps__ must be undefined, null, or an Object");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject *hallpass = JSVAL_TO_OBJECT(exposedProps);
|
||||
|
||||
Access access = NO_ACCESS;
|
||||
|
||||
jsval v;
|
||||
if (!JS_LookupPropertyById(cx, hallpass, id, &v)) {
|
||||
return false; // Error
|
||||
}
|
||||
|
||||
if (!JSVAL_IS_STRING(v)) {
|
||||
JS_ReportError(cx, "property must be a string");
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString *str = JSVAL_TO_STRING(v);
|
||||
const jschar *chars = JS_GetStringChars(str);
|
||||
size_t length = JS_GetStringLength(str);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
switch (chars[i]) {
|
||||
case 'r':
|
||||
if (access & READ) {
|
||||
JS_ReportError(cx, "duplicate 'readable' property flag");
|
||||
return false;
|
||||
}
|
||||
access = Access(access | READ);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (access & WRITE) {
|
||||
JS_ReportError(cx, "duplicate 'writable' property flag");
|
||||
return false;
|
||||
}
|
||||
access = Access(access | WRITE);
|
||||
break;
|
||||
|
||||
default:
|
||||
JS_ReportError(cx, "properties can only be readable or read and writable");
|
||||
return false;
|
||||
void
|
||||
AccessCheck::leave(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if(ssm) {
|
||||
ssm->PopContextPrincipal(cx);
|
||||
}
|
||||
}
|
||||
|
||||
if (access == NO_ACCESS) {
|
||||
JS_ReportError(cx, "specified properties must have a permission bit set");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((set && !(access & WRITE)) ||
|
||||
(!set && !(access & READ))) {
|
||||
return true; // Deny
|
||||
}
|
||||
|
||||
perm = PermitPropertyAccess;
|
||||
return true; // Allow
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -44,58 +44,14 @@ namespace xpc {
|
||||
|
||||
class AccessCheck {
|
||||
public:
|
||||
static bool isSameOrigin(JSCompartment *a, JSCompartment *b);
|
||||
static bool isChrome(JSCompartment *compartment);
|
||||
static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id, bool set);
|
||||
static bool isSystemOnlyAccessPermitted(JSContext *cx);
|
||||
|
||||
static bool needsSystemOnlyWrapper(JSObject *obj);
|
||||
static bool subsumes(JSCompartment *subject, JSCompartment *object, bool *yesno);
|
||||
static bool isPrivileged(JSCompartment *compartment);
|
||||
|
||||
static void deny(JSContext *cx, jsid id);
|
||||
};
|
||||
|
||||
struct Policy {
|
||||
typedef JSWrapper::Permission Permission;
|
||||
|
||||
static const Permission PermitObjectAccess = JSWrapper::PermitObjectAccess;
|
||||
static const Permission PermitPropertyAccess = JSWrapper::PermitPropertyAccess;
|
||||
static const Permission DenyAccess = JSWrapper::DenyAccess;
|
||||
};
|
||||
|
||||
// This policy permits access to all properties.
|
||||
struct Permissive : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm) {
|
||||
perm = PermitObjectAccess;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to the object if the subject can touch
|
||||
// system objects.
|
||||
struct OnlyIfSubjectIsSystem : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm) {
|
||||
perm = DenyAccess;
|
||||
if (AccessCheck::isSystemOnlyAccessPermitted(cx))
|
||||
perm = PermitObjectAccess;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to properties that are safe to be used
|
||||
// across origins.
|
||||
struct CrossOriginAccessiblePropertiesOnly : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm) {
|
||||
perm = DenyAccess;
|
||||
if (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, set))
|
||||
perm = PermitPropertyAccess;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// This policy only permits access to properties if they appear in the
|
||||
// objects exposed properties list.
|
||||
struct ExposedPropertiesOnly : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm);
|
||||
static bool enter(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject, jsid id,
|
||||
JSCrossCompartmentWrapper::Mode mode);
|
||||
static void leave(JSContext *cx, JSObject *wrapper, JSObject *wrappedObject);
|
||||
};
|
||||
|
||||
}
|
||||
|
244
js/src/xpconnect/src/wrappers/ChromeWrapper.cpp
Normal file
244
js/src/xpconnect/src/wrappers/ChromeWrapper.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code, released
|
||||
* June 24, 2010.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "ChromeWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
|
||||
#include "XPCWrapper.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace xpc {
|
||||
|
||||
ChromeWrapper ChromeWrapper::singleton;
|
||||
|
||||
ChromeWrapper::ChromeWrapper() : JSCrossCompartmentWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
ChromeWrapper::~ChromeWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
typedef enum { READ = (1<<0), WRITE = (1<<1), DENIED=0 } Permission;
|
||||
|
||||
static bool
|
||||
Allow(JSContext *cx, bool *yesno)
|
||||
{
|
||||
if(yesno) {
|
||||
*yesno = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
Deny(JSContext *cx, bool *yesno, const char *error)
|
||||
{
|
||||
if(yesno) {
|
||||
*yesno = false;
|
||||
return true;
|
||||
}
|
||||
JS_ReportError(cx, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckAccess(JSContext *cx, JSObject *hallpass, jsid id, JSCrossCompartmentWrapper::Mode mode,
|
||||
bool *yesno = NULL)
|
||||
{
|
||||
if(!hallpass) {
|
||||
return Allow(cx, yesno);
|
||||
}
|
||||
|
||||
Permission perm = DENIED;
|
||||
|
||||
jsval v;
|
||||
if(!JS_LookupPropertyById(cx, hallpass, id, &v)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!JSVAL_IS_STRING(v)) {
|
||||
return Deny(cx, yesno, "property permission must be a string");
|
||||
}
|
||||
|
||||
JSString *str = JSVAL_TO_STRING(v);
|
||||
const jschar *chars = JS_GetStringChars(str);
|
||||
size_t length = JS_GetStringLength(str);
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
switch (chars[i]) {
|
||||
case 'r':
|
||||
if(perm & READ) {
|
||||
return Deny(cx, yesno, "duplicate 'readable' property flag");
|
||||
}
|
||||
perm = Permission(perm | READ);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if(perm & WRITE) {
|
||||
return Deny(cx, yesno, "duplicate 'writable' property flag");
|
||||
}
|
||||
perm = Permission(perm | WRITE);
|
||||
break;
|
||||
|
||||
default:
|
||||
return Deny(cx, yesno, "property permission can only be readable or read and writable");
|
||||
}
|
||||
}
|
||||
|
||||
if(perm == DENIED) {
|
||||
return Deny(cx, yesno, "invalid property permission");
|
||||
}
|
||||
|
||||
if((mode == JSCrossCompartmentWrapper::GET && !(perm & READ)) ||
|
||||
(mode == JSCrossCompartmentWrapper::SET && !(perm & WRITE))) {
|
||||
if(yesno) {
|
||||
*yesno = false;
|
||||
return true;
|
||||
}
|
||||
AccessCheck::deny(cx, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Allow(cx, yesno);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetHallPass(JSContext *cx, JSObject *wrappedObject, jsid id, JSObject **hallpassp)
|
||||
{
|
||||
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
|
||||
|
||||
JSBool found = JS_FALSE;
|
||||
if(!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
|
||||
return false;
|
||||
if(!found) {
|
||||
*hallpassp = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
jsval exposedProps;
|
||||
if(!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
|
||||
return false;
|
||||
|
||||
if(JSVAL_IS_VOID(exposedProps) || JSVAL_IS_NULL(exposedProps)) {
|
||||
AccessCheck::deny(cx, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!JSVAL_IS_OBJECT(exposedProps)) {
|
||||
JS_ReportError(cx,
|
||||
"__exposedProps__ must be undefined, null, or an object");
|
||||
return false;
|
||||
}
|
||||
|
||||
*hallpassp = JSVAL_TO_OBJECT(exposedProps);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
Filter(JSContext *cx, JSObject *wrappedObject, AutoValueVector &props)
|
||||
{
|
||||
JSObject *hallpass;
|
||||
if(!GetHallPass(cx, wrappedObject, JSVAL_VOID, &hallpass))
|
||||
return false;
|
||||
if(!hallpass)
|
||||
return true;
|
||||
size_t w = 0;
|
||||
for (size_t n = 0; n < props.length(); ++n) {
|
||||
bool yes;
|
||||
jsid id = props[n];
|
||||
if(!CheckAccess(cx, hallpass, id, JSCrossCompartmentWrapper::GET, &yes))
|
||||
return false;
|
||||
if(yes) {
|
||||
props[w++] = id;
|
||||
}
|
||||
}
|
||||
props.resize(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return JSCrossCompartmentWrapper::getOwnPropertyNames(cx, wrapper, props) &&
|
||||
Filter(cx, wrappedObject(wrapper), props);
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return JSCrossCompartmentWrapper::enumerate(cx, wrapper, props) &&
|
||||
Filter(cx, wrappedObject(wrapper), props);
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return JSCrossCompartmentWrapper::enumerateOwn(cx, wrapper, props) &&
|
||||
Filter(cx, wrappedObject(wrapper), props);
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp)
|
||||
{
|
||||
// We refuse to trigger the iterator hook across chrome wrappers because
|
||||
// we don't know how to censor custom iterator objects. Instead we trigger
|
||||
// the default proxy iterate trap, which will ask ChromeWrapper::enumerate()
|
||||
// for the list of (consored) ids.
|
||||
return JSProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ChromeWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode)
|
||||
{
|
||||
JSObject *hallpass;
|
||||
return GetHallPass(cx, wrappedObject(wrapper), id, &hallpass) &&
|
||||
CheckAccess(cx, hallpass, id, mode);
|
||||
}
|
||||
|
||||
JSString *
|
||||
ChromeWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
|
||||
{
|
||||
// Censor Function.prototype.toString.call(wrapper) and decompile Function instead.
|
||||
JSObject *ctor;
|
||||
if(!JS_GetClassObject(cx, wrapper->getGlobal(), JSProto_Function, &ctor))
|
||||
return false;
|
||||
return JS_DecompileFunction(cx, JS_ValueToConstructor(cx, OBJECT_TO_JSVAL(ctor)), indent);
|
||||
}
|
||||
|
||||
}
|
@ -37,25 +37,26 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <jsapi.h>
|
||||
#include <jswrapper.h>
|
||||
#include "jsapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
class FilteringWrapper : public Base {
|
||||
class ChromeWrapper : public JSCrossCompartmentWrapper {
|
||||
public:
|
||||
FilteringWrapper(uintN flags);
|
||||
virtual ~FilteringWrapper();
|
||||
ChromeWrapper();
|
||||
virtual ~ChromeWrapper();
|
||||
|
||||
virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual bool enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props);
|
||||
virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp);
|
||||
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, bool set);
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode);
|
||||
|
||||
static FilteringWrapper singleton;
|
||||
virtual JSString *fun_toString(JSContext *cx, JSObject *wrapper, uintN indent);
|
||||
|
||||
static ChromeWrapper singleton;
|
||||
};
|
||||
|
||||
}
|
@ -37,30 +37,31 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
// Xray wrappers re-resolve the original native properties on the native
|
||||
// object and always directly access to those properties.
|
||||
#include "ContentWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
extern JSClass HolderClass;
|
||||
ContentWrapper ContentWrapper::singleton;
|
||||
|
||||
template <typename Base>
|
||||
class XrayWrapper : public Base {
|
||||
public:
|
||||
XrayWrapper(uintN flags);
|
||||
virtual ~XrayWrapper();
|
||||
ContentWrapper::ContentWrapper() : JSCrossCompartmentWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
|
||||
JSPropertyDescriptor *desc);
|
||||
virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp);
|
||||
ContentWrapper::~ContentWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
static XrayWrapper singleton;
|
||||
};
|
||||
bool
|
||||
ContentWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode)
|
||||
{
|
||||
return AccessCheck::enter(cx, wrapper, wrappedObject(wrapper), id, mode);
|
||||
}
|
||||
|
||||
void
|
||||
ContentWrapper::leave(JSContext *cx, JSObject *wrapper)
|
||||
{
|
||||
return AccessCheck::leave(cx, wrapper, wrappedObject(wrapper));
|
||||
}
|
||||
|
||||
}
|
@ -37,25 +37,28 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef __CrossOriginWrapper_h__
|
||||
#define __CrossOriginWrapper_h__
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jswrapper.h"
|
||||
|
||||
// Content wrappers allow unmitigated access and are only used if the
|
||||
// origin (subject) compartment's principals subsume the target (object)
|
||||
// compartment's principals.
|
||||
//
|
||||
// The main responsibility of the content wrapper is to push and pop the
|
||||
// target (object) compartment's principals when entering and leaving
|
||||
// that compartment.
|
||||
|
||||
namespace xpc {
|
||||
|
||||
class CrossOriginWrapper : public JSCrossCompartmentWrapper {
|
||||
class ContentWrapper : public JSCrossCompartmentWrapper {
|
||||
public:
|
||||
CrossOriginWrapper(uintN flags);
|
||||
virtual ~CrossOriginWrapper();
|
||||
ContentWrapper();
|
||||
virtual ~ContentWrapper();
|
||||
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, bool set);
|
||||
virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Mode mode);
|
||||
virtual void leave(JSContext *cx, JSObject *wrapper);
|
||||
|
||||
static CrossOriginWrapper singleton;
|
||||
static ContentWrapper singleton;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,89 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code, released
|
||||
* June 24, 2010.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "CrossOriginWrapper.h"
|
||||
|
||||
#include "nsJSPrincipals.h"
|
||||
|
||||
#include "XPCWrapper.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
CrossOriginWrapper::CrossOriginWrapper(uintN flags) : JSCrossCompartmentWrapper(flags)
|
||||
{
|
||||
}
|
||||
|
||||
CrossOriginWrapper::~CrossOriginWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
static nsIPrincipal *
|
||||
GetCompartmentPrincipal(JSCompartment *compartment)
|
||||
{
|
||||
return static_cast<nsJSPrincipals *>(compartment->principals)->nsIPrincipalPtr;
|
||||
}
|
||||
|
||||
bool
|
||||
CrossOriginWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, bool set)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (!ssm) {
|
||||
return true;
|
||||
}
|
||||
JSStackFrame *fp = NULL;
|
||||
nsIPrincipal *principal = GetCompartmentPrincipal(wrappedObject(wrapper)->getCompartment(cx));
|
||||
nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Not allowing call because we're out of memory");
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CrossOriginWrapper::leave(JSContext *cx, JSObject *wrapper)
|
||||
{
|
||||
nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
|
||||
if (ssm) {
|
||||
ssm->PopContextPrincipal(cx);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code, released
|
||||
* June 24, 2010.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "FilteringWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "CrossOriginWrapper.h"
|
||||
#include "XrayWrapper.h"
|
||||
|
||||
#include "XPCWrapper.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace xpc {
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
FilteringWrapper<Base, Policy>::FilteringWrapper(uintN flags) : Base(flags)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
FilteringWrapper<Base, Policy>::~FilteringWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
typedef JSWrapper::Permission Permission;
|
||||
|
||||
static const Permission PermitObjectAccess = JSWrapper::PermitObjectAccess;
|
||||
static const Permission PermitPropertyAccess = JSWrapper::PermitPropertyAccess;
|
||||
static const Permission DenyAccess = JSWrapper::DenyAccess;
|
||||
|
||||
template <typename Policy>
|
||||
static bool
|
||||
Filter(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
size_t w = 0;
|
||||
for (size_t n = 0; n < props.length(); ++n) {
|
||||
jsid id = props[n];
|
||||
Permission perm;
|
||||
if (perm != PermitObjectAccess && !Policy::check(cx, wrapper, id, false, perm))
|
||||
return false; // Error
|
||||
if (perm != DenyAccess) {
|
||||
props[w++] = id;
|
||||
}
|
||||
}
|
||||
props.resize(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
static bool
|
||||
CheckAndReport(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission &perm)
|
||||
{
|
||||
if (!Policy::check(cx, wrapper, id, set, perm)) {
|
||||
return false;
|
||||
}
|
||||
if (perm == DenyAccess) {
|
||||
AccessCheck::deny(cx, id);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return Base::getOwnPropertyNames(cx, wrapper, props) &&
|
||||
Filter<Policy>(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return Base::enumerate(cx, wrapper, props) &&
|
||||
Filter<Policy>(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props)
|
||||
{
|
||||
return Base::enumerateOwn(cx, wrapper, props) &&
|
||||
Filter<Policy>(cx, wrapper, props);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp)
|
||||
{
|
||||
// We refuse to trigger the iterator hook across chrome wrappers because
|
||||
// we don't know how to censor custom iterator objects. Instead we trigger
|
||||
// the default proxy iterate trap, which will ask enumerate() for the list
|
||||
// of (consored) ids.
|
||||
return JSProxyHandler::iterate(cx, wrapper, flags, vp);
|
||||
}
|
||||
|
||||
template <typename Base, typename Policy>
|
||||
bool
|
||||
FilteringWrapper<Base, Policy>::enter(JSContext *cx, JSObject *wrapper, jsid id, bool set)
|
||||
{
|
||||
Permission perm;
|
||||
return CheckAndReport<Policy>(cx, wrapper, JSVAL_VOID, set, perm) &&
|
||||
Base::enter(cx, wrapper, id, set);
|
||||
}
|
||||
|
||||
#define SOW FilteringWrapper<JSCrossCompartmentWrapper, OnlyIfSubjectIsSystem>
|
||||
#define COW FilteringWrapper<JSCrossCompartmentWrapper, ExposedPropertiesOnly>
|
||||
#define XOW FilteringWrapper<XrayWrapper<CrossOriginWrapper>, CrossOriginAccessiblePropertiesOnly>
|
||||
|
||||
template<> SOW SOW::singleton(0);
|
||||
template<> COW COW::singleton(0);
|
||||
template<> XOW XOW::singleton(0);
|
||||
|
||||
template class SOW;
|
||||
template class COW;
|
||||
template class XOW;
|
||||
|
||||
}
|
@ -47,10 +47,9 @@ LIBRARY_NAME = xpcwrappers_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
CPPSRCS = AccessCheck.cpp \
|
||||
CrossOriginWrapper.cpp \
|
||||
FilteringWrapper.cpp \
|
||||
XrayWrapper.cpp \
|
||||
CPPSRCS = ContentWrapper.cpp \
|
||||
ChromeWrapper.cpp \
|
||||
AccessCheck.cpp \
|
||||
WrapperFactory.cpp
|
||||
|
||||
LOCAL_INCLUDES = \
|
||||
|
@ -37,79 +37,20 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "WrapperFactory.h"
|
||||
#include "CrossOriginWrapper.h"
|
||||
#include "FilteringWrapper.h"
|
||||
#include "XrayWrapper.h"
|
||||
#include "ContentWrapper.h"
|
||||
#include "ChromeWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
|
||||
#include "xpcprivate.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
// When chrome pulls a naked property across the membrane using
|
||||
// .wrappedJSObject, we want it to cross the membrane into the
|
||||
// chrome compartment without automatically being wrapped into an
|
||||
// X-ray wrapper. We achieve this by wrapping it into a special
|
||||
// transparent wrapper in the origin (non-chrome) compartment. When
|
||||
// an object with that special wrapper applied crosses into chrome,
|
||||
// we know to not apply an X-ray wrapper.
|
||||
JSWrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
||||
|
||||
// When objects for which we waived the X-ray wrapper cross into
|
||||
// chrome, we wrap them into a special cross-compartment wrapper
|
||||
// that transitively extends the waiver to all properties we get
|
||||
// off it.
|
||||
JSCrossCompartmentWrapper XrayWrapperWaivedWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
|
||||
|
||||
JSObject *
|
||||
WrapperFactory::Rewrap(JSContext *cx, JSObject *obj, JSObject *wrappedProto, uintN flags)
|
||||
JSCrossCompartmentWrapper *
|
||||
WrapperFactory::select(JSContext *cx, JSCompartment *subject, JSCompartment *object)
|
||||
{
|
||||
NS_ASSERTION(!obj->isWrapper(), "wrapped object passed to rewrap");
|
||||
|
||||
JSCompartment *origin = obj->getCompartment(cx);
|
||||
JSCompartment *target = cx->compartment;
|
||||
|
||||
JSWrapper *wrapper;
|
||||
if (AccessCheck::isChrome(target)) {
|
||||
NS_ASSERTION(!AccessCheck::isChrome(origin), "we shouldn't rewrap from chrome into chrome");
|
||||
|
||||
// If we waived the X-ray wrapper for this object, wrap it into a
|
||||
// special wrapper to transitively maintain the X-ray waiver.
|
||||
if (flags & WAIVE_XRAY_WRAPPER_FLAG) {
|
||||
wrapper = &XrayWrapperWaivedWrapper;
|
||||
} else {
|
||||
// Native objects must be wrapped into an X-ray wrapper.
|
||||
wrapper = IS_WN_WRAPPER_OBJECT(obj)
|
||||
? &XrayWrapper<JSCrossCompartmentWrapper>::singleton
|
||||
: &JSCrossCompartmentWrapper::singleton;
|
||||
if(AccessCheck::isPrivileged(object)) {
|
||||
return &ChromeWrapper::singleton;
|
||||
}
|
||||
} else if (AccessCheck::isChrome(origin)) {
|
||||
// If an object that needs a system only wrapper crosses into content
|
||||
// from chrome, we have to wrap it into a system only wrapper on the
|
||||
// fly. In this case we don't need to restrict to exposed properties
|
||||
// since only privileged content will be allowed to touch it anyway.
|
||||
if (AccessCheck::needsSystemOnlyWrapper(obj)) {
|
||||
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
||||
OnlyIfSubjectIsSystem>::singleton;
|
||||
} else {
|
||||
wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
|
||||
ExposedPropertiesOnly>::singleton;
|
||||
}
|
||||
} else if (AccessCheck::isSameOrigin(origin, target)) {
|
||||
// Same origin we use a transparent wrapper;
|
||||
wrapper = &JSCrossCompartmentWrapper::singleton;
|
||||
} else {
|
||||
// Cross origin we want to disallow scripting and limit access to
|
||||
// a predefined set of properties. XrayWrapper adds a property
|
||||
// (.wrappedJSObject) which allows bypassing the XrayWrapper, but
|
||||
// we filter out access to that property.
|
||||
wrapper = &FilteringWrapper<XrayWrapper<CrossOriginWrapper>,
|
||||
CrossOriginAccessiblePropertiesOnly>::singleton;
|
||||
}
|
||||
return JSWrapper::New(cx, obj, wrappedProto, NULL, wrapper);
|
||||
return &ContentWrapper::singleton;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,21 +43,10 @@
|
||||
namespace xpc {
|
||||
|
||||
class WrapperFactory {
|
||||
public:
|
||||
enum { WAIVE_XRAY_WRAPPER_FLAG = (1<<0) };
|
||||
|
||||
// Return true if any of any of the nested wrappers have the flag set.
|
||||
bool HasWrapperFlag(JSObject *wrapper, uintN flag) {
|
||||
uintN flags = 0;
|
||||
wrapper->unwrap(&flags);
|
||||
return !!(flags & flag);
|
||||
}
|
||||
|
||||
// Rewrap an object that is about to cross compartment boundaries.
|
||||
static JSObject *Rewrap(JSContext *cx,
|
||||
JSObject *obj,
|
||||
JSObject *wrappedProto,
|
||||
uintN flags);
|
||||
// Return the wrapper handler to use, or NULL in case of error.
|
||||
static JSCrossCompartmentWrapper *select(JSContext *cx,
|
||||
JSCompartment *subject,
|
||||
JSCompartment *object);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,323 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code, released
|
||||
* June 24, 2010.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation
|
||||
*
|
||||
* Contributor(s):
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "XrayWrapper.h"
|
||||
#include "AccessCheck.h"
|
||||
#include "FilteringWrapper.h"
|
||||
#include "CrossOriginWrapper.h"
|
||||
#include "WrapperFactory.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "XPCWrapper.h"
|
||||
#include "xpcprivate.h"
|
||||
|
||||
namespace xpc {
|
||||
|
||||
using namespace js;
|
||||
|
||||
static const uint32 JSSLOT_WN_OBJ = JSSLOT_PRIVATE;
|
||||
|
||||
static JSBool
|
||||
holder_get(JSContext *cx, JSObject *holder, jsid id, jsval *vp);
|
||||
|
||||
static JSBool
|
||||
holder_set(JSContext *cx, JSObject *holder, jsid id, jsval *vp);
|
||||
|
||||
static JSBool
|
||||
holder_enumerate(JSContext *cx, JSObject *holder);
|
||||
|
||||
JSClass HolderClass = {
|
||||
"NativePropertyHolder",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(1),
|
||||
JS_PropertyStub, JS_PropertyStub, holder_get, holder_set,
|
||||
holder_enumerate, JS_ResolveStub, JS_ConvertStub, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
template <typename Base>
|
||||
XrayWrapper<Base>::XrayWrapper(uintN flags) : Base(flags)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
XrayWrapper<Base>::~XrayWrapper()
|
||||
{
|
||||
}
|
||||
|
||||
static XPCWrappedNative *
|
||||
GetWrappedNative(JSObject *obj)
|
||||
{
|
||||
NS_ASSERTION(IS_WN_WRAPPER_OBJECT(obj), "expected a wrapped native here");
|
||||
return static_cast<XPCWrappedNative *>(obj->getPrivate());
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
GetWrappedNativeObjectFromHolder(JSObject *holder)
|
||||
{
|
||||
NS_ASSERTION(holder->getClass() == &HolderClass, "expected a native property holder object");
|
||||
return JSVAL_TO_OBJECT(holder->getSlot(JSSLOT_WN_OBJ));
|
||||
}
|
||||
|
||||
// Some DOM objects have shared properties that don't have an explicit
|
||||
// getter/setter and rely on the class getter/setter. We install a
|
||||
// class getter/setter on the holder object to trigger them.
|
||||
static JSBool
|
||||
holder_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSObject *wnObject = GetWrappedNativeObjectFromHolder(obj);
|
||||
XPCWrappedNative *wn = GetWrappedNative(wnObject);
|
||||
if (NATIVE_HAS_FLAG(wn, WantGetProperty)) {
|
||||
JSBool retval = true;
|
||||
nsresult rv = wn->GetScriptableCallback()->GetProperty(wn, cx, obj, id, vp, &retval);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (retval) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
holder_set(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
JSObject *wnObject = GetWrappedNativeObjectFromHolder(obj);
|
||||
XPCWrappedNative *wn = GetWrappedNative(wnObject);
|
||||
if (NATIVE_HAS_FLAG(wn, WantSetProperty)) {
|
||||
JSBool retval = true;
|
||||
nsresult rv = wn->GetScriptableCallback()->SetProperty(wn, cx, obj, id, vp, &retval);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (retval) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ResolveNativeProperty(JSContext *cx, JSObject *holder, jsval id, bool set, JSPropertyDescriptor *desc)
|
||||
{
|
||||
desc->obj = NULL;
|
||||
|
||||
NS_ASSERTION(holder->getClass() == &HolderClass, "expected a native property holder object");
|
||||
JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
|
||||
XPCWrappedNative *wn = GetWrappedNative(wnObject);
|
||||
|
||||
// This will do verification and the method lookup for us.
|
||||
XPCCallContext ccx(JS_CALLER, cx, holder, nsnull, id);
|
||||
|
||||
// Run the resolve hook of the wrapped native.
|
||||
JSBool retval = true;
|
||||
JSObject *pobj = NULL;
|
||||
uintN flags = cx->resolveFlags | (set ? JSRESOLVE_ASSIGNING : 0);
|
||||
nsresult rv = wn->GetScriptableInfo()->GetCallback()->NewResolve(wn, cx, holder, id, flags,
|
||||
&pobj, &retval);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (retval) {
|
||||
XPCThrower::Throw(rv, cx);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pobj) {
|
||||
return JS_GetPropertyDescriptorById(cx, pobj, id, cx->resolveFlags, desc);
|
||||
}
|
||||
|
||||
// There are no native numeric properties, so we can shortcut here. We will not
|
||||
// find the property.
|
||||
if (!JSID_IS_ATOM(id)) {
|
||||
/* Not found */
|
||||
return true;
|
||||
}
|
||||
|
||||
XPCNativeInterface *iface;
|
||||
XPCNativeMember *member;
|
||||
if (ccx.GetWrapper() != wn ||
|
||||
!wn->IsValid() ||
|
||||
!(iface = ccx.GetInterface()) ||
|
||||
!(member = ccx.GetMember())) {
|
||||
/* Not found */
|
||||
return true;
|
||||
}
|
||||
|
||||
desc->obj = holder;
|
||||
desc->attrs = JSPROP_ENUMERATE;
|
||||
desc->getter = NULL;
|
||||
desc->setter = NULL;
|
||||
desc->shortid = NULL;
|
||||
desc->value = JSVAL_VOID;
|
||||
|
||||
if (member->IsConstant()) {
|
||||
if (!member->GetConstantValue(ccx, iface, &desc->value)) {
|
||||
JS_ReportError(cx, "Failed to convert constant native property to JS value");
|
||||
return false;
|
||||
}
|
||||
} else if (member->IsAttribute()) {
|
||||
// This is a getter/setter. Clone a function for it.
|
||||
jsval fval;
|
||||
if (!member->NewFunctionObject(ccx, iface, wnObject, &fval)) {
|
||||
JS_ReportError(cx, "Failed to clone function object for native getter/setter");
|
||||
return false;
|
||||
}
|
||||
desc->getter = CastAsPropertyOp(JSVAL_TO_OBJECT(fval));
|
||||
desc->attrs |= JSPROP_GETTER;
|
||||
if (member->IsWritableAttribute()) {
|
||||
desc->setter = desc->getter;;
|
||||
desc->attrs |= JSPROP_SETTER;
|
||||
}
|
||||
|
||||
// Make the property shared on the holder so no slot is allocated
|
||||
// for it. This avoids keeping garbage alive through that slot.
|
||||
desc->attrs |= JSPROP_SHARED;
|
||||
} else {
|
||||
// This is a method. Clone a function for it.
|
||||
if (!member->NewFunctionObject(ccx, iface, wnObject, &desc->value)) {
|
||||
JS_ReportError(cx, "Failed to clone function object for native function");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Without a wrapper the function would live on the prototype. Since we
|
||||
// don't have one, we have to avoid calling the scriptable helper's
|
||||
// GetProperty method for this property, so stub out the getter and
|
||||
// setter here explicitly.
|
||||
desc->getter = desc->setter = JS_PropertyStub;
|
||||
}
|
||||
|
||||
// Define the property.
|
||||
return JS_DefinePropertyById(cx, holder, id, desc->value,
|
||||
desc->getter, desc->setter, desc->attrs);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
holder_enumerate(JSContext *cx, JSObject *holder)
|
||||
{
|
||||
// Ask the native wrapper for all its ids
|
||||
JSIdArray *ida = JS_Enumerate(cx, GetWrappedNativeObjectFromHolder(holder));
|
||||
if (!ida)
|
||||
return false;
|
||||
jsid *idp = ida->vector;
|
||||
size_t length = ida->length;
|
||||
// Resolve the underlyign native properties onto the holder object
|
||||
while (length-- > 0) {
|
||||
JSPropertyDescriptor dummy;
|
||||
if (!ResolveNativeProperty(cx, holder, *idp++, false, &dummy))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NativePropertiesOnly : public Policy {
|
||||
static bool check(JSContext *cx, JSObject *obj, jsid id, bool set, Permission &perm);
|
||||
};
|
||||
|
||||
extern JSWrapper WaiveXrayWrapperWrapper;
|
||||
|
||||
static JSBool
|
||||
wrappedJSObject_getter(JSContext *cx, JSObject *holder, jsid id, jsval *vp)
|
||||
{
|
||||
// If the caller intentionally waives the X-ray wrapper we usually
|
||||
// apply for wrapped natives, use a special wrapper to make sure the
|
||||
// membrane will not automatically apply an X-ray wrapper.
|
||||
JSObject *wn = GetWrappedNativeObjectFromHolder(holder);
|
||||
JSObject *obj = JSWrapper::New(cx, wn, NULL, wn->getParent(), &WaiveXrayWrapperWrapper);
|
||||
if (!obj)
|
||||
return false;
|
||||
*vp = OBJECT_TO_JSVAL(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
bool
|
||||
XrayWrapper<Base>::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc)
|
||||
{
|
||||
if (id == XPCJSRuntime::IDX_WRAPPED_JSOBJECT) {
|
||||
desc->obj = wrapper;
|
||||
desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
|
||||
desc->getter = wrappedJSObject_getter;
|
||||
desc->setter = NULL;
|
||||
desc->shortid = NULL;
|
||||
desc->value = JSVAL_VOID;
|
||||
return true;
|
||||
}
|
||||
if (!Base::getPropertyDescriptor(cx, wrapper, id, desc)) {
|
||||
return false;
|
||||
}
|
||||
if (desc->obj)
|
||||
return true;
|
||||
return ResolveNativeProperty(cx, Base::wrappedObject(wrapper), id, false, desc);
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
bool
|
||||
XrayWrapper<Base>::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc)
|
||||
{
|
||||
return getPropertyDescriptor(cx, wrapper, id, desc);
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
bool
|
||||
XrayWrapper<Base>::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
// Use the default implementation, which forwards to getPropertyDescriptor.
|
||||
return JSProxyHandler::has(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
bool
|
||||
XrayWrapper<Base>::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
|
||||
{
|
||||
// Use the default implementation, which forwards to getOwnPropertyDescriptor.
|
||||
return JSProxyHandler::hasOwn(cx, wrapper, id, bp);
|
||||
}
|
||||
|
||||
#define SJOW XrayWrapper<JSCrossCompartmentWrapper>
|
||||
#define XOSJOW XrayWrapper<CrossOriginWrapper>
|
||||
|
||||
template <> SJOW SJOW::singleton(0);
|
||||
template <> XOSJOW XOSJOW::singleton(0);
|
||||
|
||||
template class SJOW;
|
||||
template class XOSJOW;
|
||||
|
||||
}
|
@ -1391,7 +1391,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||
|
||||
jsval wrappedObjVal = OBJECT_TO_JSVAL(destObj);
|
||||
AUTO_MARK_JSVAL(ccx, &wrappedObjVal);
|
||||
if(wrapper->NeedsSOW())
|
||||
if(wrapper->NeedsChromeWrapper())
|
||||
{
|
||||
using SystemOnlyWrapper::WrapObject;
|
||||
if(!WrapObject(ccx, xpcscope->GetGlobalJSObject(),
|
||||
@ -1419,7 +1419,7 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||
|
||||
AUTO_MARK_JSVAL(ccx, &v);
|
||||
return XPCCrossOriginWrapper::WrapObject(ccx, scope, &v) &&
|
||||
(!wrapper->NeedsSOW() ||
|
||||
(!wrapper->NeedsChromeWrapper() ||
|
||||
SystemOnlyWrapper::WrapObject(ccx, xpcscope->GetGlobalJSObject(),
|
||||
v, &v)) &&
|
||||
CreateHolderIfNeeded(ccx, JSVAL_TO_OBJECT(v), d, dest);
|
||||
@ -1428,12 +1428,12 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx,
|
||||
*d = v;
|
||||
if(allowNativeWrapper)
|
||||
{
|
||||
if(wrapper->NeedsSOW())
|
||||
if(wrapper->NeedsChromeWrapper())
|
||||
if(!SystemOnlyWrapper::WrapObject(ccx,
|
||||
xpcscope->GetGlobalJSObject(),
|
||||
v, d))
|
||||
return JS_FALSE;
|
||||
if(wrapper->NeedsCOW())
|
||||
if(wrapper->IsDoubleWrapper())
|
||||
if(!ChromeObjectWrapper::WrapObject(ccx, xpcscope->GetGlobalJSObject(), v, d))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -2632,10 +2632,10 @@ public:
|
||||
|
||||
JSBool HasExternalReference() const {return mRefCnt > 1;}
|
||||
|
||||
JSBool NeedsSOW() { return !!(mWrapperWord & NEEDS_SOW); }
|
||||
void SetNeedsSOW() { mWrapperWord |= NEEDS_SOW; }
|
||||
JSBool NeedsCOW() { return !!(mWrapperWord & NEEDS_COW); }
|
||||
void SetNeedsCOW() { mWrapperWord |= NEEDS_COW; }
|
||||
JSBool NeedsChromeWrapper() { return !!(mWrapperWord & CHROME_ONLY); }
|
||||
void SetNeedsChromeWrapper() { mWrapperWord |= CHROME_ONLY; }
|
||||
JSBool IsDoubleWrapper() { return !!(mWrapperWord & DOUBLE_WRAPPER); }
|
||||
void SetIsDoubleWrapper() { mWrapperWord |= DOUBLE_WRAPPER; }
|
||||
JSBool NeedsXOW() { return !!(mWrapperWord & NEEDS_XOW); }
|
||||
|
||||
JSObject* GetWrapper()
|
||||
@ -2644,13 +2644,13 @@ public:
|
||||
}
|
||||
void SetWrapper(JSObject *obj)
|
||||
{
|
||||
PRWord needsSOW = NeedsSOW() ? NEEDS_SOW : 0;
|
||||
PRWord needsCOW = NeedsCOW() ? NEEDS_COW : 0;
|
||||
PRWord needsChrome = NeedsChromeWrapper() ? CHROME_ONLY : 0;
|
||||
PRWord doubleWrapper = IsDoubleWrapper() ? DOUBLE_WRAPPER : 0;
|
||||
PRWord needsXOW = NeedsXOW() ? NEEDS_XOW : 0;
|
||||
mWrapperWord = PRWord(obj) |
|
||||
needsSOW |
|
||||
needsCOW |
|
||||
needsXOW;
|
||||
needsXOW |
|
||||
doubleWrapper |
|
||||
needsChrome;
|
||||
}
|
||||
|
||||
void NoteTearoffs(nsCycleCollectionTraversalCallback& cb);
|
||||
@ -2687,8 +2687,8 @@ protected:
|
||||
|
||||
private:
|
||||
enum {
|
||||
NEEDS_SOW = JS_BIT(0),
|
||||
NEEDS_COW = JS_BIT(1),
|
||||
CHROME_ONLY = JS_BIT(0),
|
||||
DOUBLE_WRAPPER = JS_BIT(1),
|
||||
NEEDS_XOW = JS_BIT(2),
|
||||
|
||||
LAST_FLAG = NEEDS_XOW
|
||||
|
@ -428,8 +428,8 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
jsval newParentVal = JSVAL_NULL;
|
||||
XPCMarkableJSVal newParentVal_markable(&newParentVal);
|
||||
AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
|
||||
JSBool needsSOW = JS_FALSE;
|
||||
JSBool needsCOW = JS_FALSE;
|
||||
JSBool chromeOnly = JS_FALSE;
|
||||
JSBool crossDoubleWrapped = JS_FALSE;
|
||||
JSBool needsXOW = JS_FALSE;
|
||||
|
||||
if(sciWrapper.GetFlags().WantPreCreate())
|
||||
@ -441,7 +441,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
return rv;
|
||||
|
||||
if(rv == NS_SUCCESS_CHROME_ACCESS_ONLY)
|
||||
needsSOW = JS_TRUE;
|
||||
chromeOnly = JS_TRUE;
|
||||
else if(rv == NS_SUCCESS_NEEDS_XOW)
|
||||
needsXOW = JS_TRUE;
|
||||
rv = NS_OK;
|
||||
@ -517,7 +517,7 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
JS_GetGlobalForObject(ccx, obj)->isSystem()) &&
|
||||
!Scope->GetGlobalJSObject()->isSystem())
|
||||
{
|
||||
needsCOW = JS_TRUE;
|
||||
crossDoubleWrapped = JS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -590,10 +590,10 @@ XPCWrappedNative::GetNewOrUsed(XPCCallContext& ccx,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if(needsSOW)
|
||||
wrapper->SetNeedsSOW();
|
||||
if(needsCOW)
|
||||
wrapper->SetNeedsCOW();
|
||||
if(chromeOnly)
|
||||
wrapper->SetNeedsChromeWrapper();
|
||||
if(crossDoubleWrapped)
|
||||
wrapper->SetIsDoubleWrapper();
|
||||
|
||||
return FinishCreate(ccx, Scope, Interface, cache, wrapper, resultWrapper);
|
||||
}
|
||||
|
@ -1088,9 +1088,9 @@ XPCWrappedNativeScope::GetWrapperFor(JSContext *cx, JSObject *obj,
|
||||
|
||||
if(wrapper)
|
||||
{
|
||||
NS_ASSERTION(!wrapper->NeedsCOW(),
|
||||
NS_ASSERTION(!wrapper->IsDoubleWrapper(),
|
||||
"chrome object that's double wrapped makes no sense");
|
||||
if(wrapper->NeedsSOW())
|
||||
if(wrapper->NeedsChromeWrapper())
|
||||
return WrapperType(SOW | hint);
|
||||
}
|
||||
|
||||
@ -1116,9 +1116,9 @@ XPCWrappedNativeScope::GetWrapperFor(JSContext *cx, JSObject *obj,
|
||||
// NB: obj2 controls whether or not this is actually a "wrapped native".
|
||||
if(wrapper)
|
||||
{
|
||||
if(wrapper->NeedsSOW())
|
||||
if(wrapper->NeedsChromeWrapper())
|
||||
return WrapperType(SOW | (hint & (SJOW | XPCNW_EXPLICIT | COW)));
|
||||
if(wrapper->NeedsCOW())
|
||||
if(wrapper->IsDoubleWrapper())
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user