bool InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id, MutableHandle<JSPropertyDescriptor> descriptor) { // We only want to do interpostion on DOM instances and // wrapped natives. RootedObject unwrapped(cx, UncheckedUnwrap(target)); const js::Class* clasp = js::GetObjectClass(unwrapped); if (!mozilla::dom::IsDOMClass(clasp) && !IS_WN_CLASS(clasp) && !IS_PROTO_CLASS(clasp) && clasp != &OuterWindowProxyClass) { return true; } XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx)); MOZ_ASSERT(scope->HasInterposition()); nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition(); JSAddonId* addonId = AddonIdOfObject(target); RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId))); RootedValue prop(cx, IdToValue(id)); RootedValue targetValue(cx, ObjectValue(*target)); RootedValue descriptorVal(cx); nsresult rv = interp->InterposeProperty(addonIdValue, targetValue, iid, prop, &descriptorVal); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } if (!descriptorVal.isObject()) return true; // We need to be careful parsing descriptorVal. |cx| is in the compartment // of the add-on and the descriptor is in the compartment of the // interposition. We could wrap the descriptor in the add-on's compartment // and then parse it. However, parsing the descriptor fetches properties // from it, and we would try to interpose on those property accesses. So // instead we parse in the interposition's compartment and then wrap the // descriptor. { JSAutoCompartment ac(cx, &descriptorVal.toObject()); if (!JS::ObjectToCompletePropertyDescriptor(cx, target, descriptorVal, descriptor)) return false; } // Always make the property non-configurable regardless of what the // interposition wants. descriptor.setAttributes(descriptor.attributes() | JSPROP_PERMANENT); if (!JS_WrapPropertyDescriptor(cx, descriptor)) return false; return true; }
JSObject * WrapperFactory::WaiveXray(JSContext *cx, JSObject *objArg) { RootedObject obj(cx, objArg); obj = UncheckedUnwrap(obj); MOZ_ASSERT(!js::IsInnerObject(obj)); JSObject *waiver = GetXrayWaiver(obj); if (waiver) return waiver; return CreateXrayWaiver(cx, obj); }
JSObject * WrapperFactory::GetXrayWaiver(JSObject *obj) { // Object should come fully unwrapped but outerized. MOZ_ASSERT(obj == UncheckedUnwrap(obj)); MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject); XPCWrappedNativeScope *scope = GetObjectScope(obj); MOZ_ASSERT(scope); if (!scope->mWaiverWrapperMap) return NULL; return xpc_UnmarkGrayObject(scope->mWaiverWrapperMap->Find(obj)); }
JSObject * WrapperFactory::GetXrayWaiver(HandleObject obj) { // Object should come fully unwrapped but outerized. MOZ_ASSERT(obj == UncheckedUnwrap(obj)); MOZ_ASSERT(!js::GetObjectClass(obj)->ext.outerObject); XPCWrappedNativeScope *scope = GetObjectScope(obj); MOZ_ASSERT(scope); if (!scope->mWaiverWrapperMap) return nullptr; JSObject* xrayWaiver = scope->mWaiverWrapperMap->Find(obj); if (xrayWaiver) JS::ExposeObjectToActiveJS(xrayWaiver); return xrayWaiver; }
bool InterposeCall(JSContext* cx, JS::HandleObject target, const JS::CallArgs& args, bool* done) { *done = false; XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx)); MOZ_ASSERT(scope->HasInterposition()); nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition(); RootedObject unwrappedTarget(cx, UncheckedUnwrap(target)); XPCWrappedNativeScope* targetScope = ObjectScope(unwrappedTarget); bool hasInterpostion = targetScope->HasCallInterposition(); if (!hasInterpostion) return true; // If there is a call interpostion, we don't want to propogate the // call to Base: *done = true; JSAddonId* addonId = AddonIdOfObject(target); RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId))); RootedValue targetValue(cx, ObjectValue(*target)); RootedValue thisValue(cx, args.thisv()); RootedObject argsArray(cx, ConvertArgsToArray(cx, args)); if (!argsArray) return false; RootedValue argsVal(cx, ObjectValue(*argsArray)); RootedValue returnVal(cx); nsresult rv = interp->InterposeCall(addonIdValue, targetValue, thisValue, argsVal, args.rval()); if (NS_FAILED(rv)) { xpc::Throw(cx, rv); return false; } return true; }