1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "RemoteObjectProxy.h"
8 #include "AccessCheck.h"
9 #include "jsfriendapi.h"
10 #include "js/Object.h" // JS::GetClass
11 #include "xpcprivate.h"
13 namespace mozilla::dom
{
15 bool RemoteObjectProxyBase::getOwnPropertyDescriptor(
16 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
, JS::Handle
<jsid
> aId
,
17 JS::MutableHandle
<Maybe
<JS::PropertyDescriptor
>> aDesc
) const {
18 bool ok
= CrossOriginGetOwnPropertyHelper(aCx
, aProxy
, aId
, aDesc
);
19 if (!ok
|| aDesc
.isSome()) {
23 return CrossOriginPropertyFallback(aCx
, aProxy
, aId
, aDesc
);
26 bool RemoteObjectProxyBase::defineProperty(
27 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
, JS::Handle
<jsid
> aId
,
28 JS::Handle
<JS::PropertyDescriptor
> aDesc
,
29 JS::ObjectOpResult
& aResult
) const {
30 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-defineownproperty
32 // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty
34 return ReportCrossOriginDenial(aCx
, aId
, "define"_ns
);
37 bool RemoteObjectProxyBase::ownPropertyKeys(
38 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
39 JS::MutableHandleVector
<jsid
> aProps
) const {
40 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
42 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
43 JS::Rooted
<JSObject
*> holder(aCx
);
44 if (!EnsureHolder(aCx
, aProxy
, &holder
) ||
45 !js::GetPropertyKeys(aCx
, holder
,
46 JSITER_OWNONLY
| JSITER_HIDDEN
| JSITER_SYMBOLS
,
51 // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
53 return xpc::AppendCrossOriginWhitelistedPropNames(aCx
, aProps
);
56 bool RemoteObjectProxyBase::delete_(JSContext
* aCx
,
57 JS::Handle
<JSObject
*> aProxy
,
59 JS::ObjectOpResult
& aResult
) const {
60 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-delete
62 // https://html.spec.whatwg.org/multipage/browsers.html#location-delete step 2
63 return ReportCrossOriginDenial(aCx
, aId
, "delete"_ns
);
66 bool RemoteObjectProxyBase::getPrototypeIfOrdinary(
67 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
, bool* aIsOrdinary
,
68 JS::MutableHandle
<JSObject
*> aProtop
) const {
69 // WindowProxy's and Location's [[GetPrototypeOf]] traps aren't the ordinary
72 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof
73 // https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof
75 // We nonetheless can implement it with a static [[Prototype]], because the
76 // [[GetPrototypeOf]] trap should always return null.
82 bool RemoteObjectProxyBase::preventExtensions(
83 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
84 JS::ObjectOpResult
& aResult
) const {
85 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-preventextensions
87 // https://html.spec.whatwg.org/multipage/browsers.html#location-preventextensions
88 return aResult
.failCantPreventExtensions();
91 bool RemoteObjectProxyBase::isExtensible(JSContext
* aCx
,
92 JS::Handle
<JSObject
*> aProxy
,
93 bool* aExtensible
) const {
94 // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-isextensible
96 // https://html.spec.whatwg.org/multipage/browsers.html#location-isextensible
101 bool RemoteObjectProxyBase::get(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
102 JS::Handle
<JS::Value
> aReceiver
,
103 JS::Handle
<jsid
> aId
,
104 JS::MutableHandle
<JS::Value
> aVp
) const {
105 return CrossOriginGet(aCx
, aProxy
, aReceiver
, aId
, aVp
);
108 bool RemoteObjectProxyBase::set(JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
109 JS::Handle
<jsid
> aId
,
110 JS::Handle
<JS::Value
> aValue
,
111 JS::Handle
<JS::Value
> aReceiver
,
112 JS::ObjectOpResult
& aResult
) const {
113 return CrossOriginSet(aCx
, aProxy
, aId
, aValue
, aReceiver
, aResult
);
116 bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys(
117 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
,
118 JS::MutableHandleVector
<jsid
> aProps
) const {
122 const char* RemoteObjectProxyBase::className(
123 JSContext
* aCx
, JS::Handle
<JSObject
*> aProxy
) const {
124 MOZ_ASSERT(js::IsProxy(aProxy
));
126 return NamesOfInterfacesWithProtos(mPrototypeID
);
129 void RemoteObjectProxyBase::GetOrCreateProxyObject(
130 JSContext
* aCx
, void* aNative
, const JSClass
* aClasp
,
131 JS::Handle
<JSObject
*> aTransplantTo
, JS::MutableHandle
<JSObject
*> aProxy
,
132 bool& aNewObjectCreated
) const {
133 xpc::CompartmentPrivate
* priv
=
134 xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx
));
135 xpc::CompartmentPrivate::RemoteProxyMap
& map
= priv
->GetRemoteProxyMap();
136 if (auto result
= map
.lookup(aNative
)) {
137 MOZ_RELEASE_ASSERT(!aTransplantTo
,
138 "GOCPO failed by finding an existing value");
140 aProxy
.set(result
->value());
142 // During a transplant, we put an object that is temporarily not a
143 // proxy object into the map. Make sure that we don't return one of
144 // these objects in the middle of a transplant.
145 MOZ_RELEASE_ASSERT(JS::GetClass(aProxy
) == aClasp
);
150 js::ProxyOptions options
;
151 options
.setClass(aClasp
);
152 JS::Rooted
<JS::Value
> native(aCx
, JS::PrivateValue(aNative
));
153 JS::Rooted
<JSObject
*> obj(
154 aCx
, js::NewProxyObject(aCx
, this, native
, nullptr, options
));
156 MOZ_RELEASE_ASSERT(!aTransplantTo
, "GOCPO failed at NewProxyObject");
161 if (!JS_SetImmutablePrototype(aCx
, obj
, &success
)) {
162 MOZ_RELEASE_ASSERT(!aTransplantTo
,
163 "GOCPO failed at JS_SetImmutablePrototype");
168 aNewObjectCreated
= true;
170 // If we're transplanting onto an object, we want to make sure that it does
171 // not have the same class as aClasp to ensure that the release assert earlier
172 // in this function will actually fire if we try to return a proxy object in
173 // the middle of a transplant.
174 MOZ_RELEASE_ASSERT(!aTransplantTo
|| (JS::GetClass(aTransplantTo
) != aClasp
),
175 "GOCPO failed by not changing the class");
177 if (!map
.put(aNative
, aTransplantTo
? aTransplantTo
: obj
)) {
178 MOZ_RELEASE_ASSERT(!aTransplantTo
, "GOCPO failed at map.put");
185 const char RemoteObjectProxyBase::sCrossOriginProxyFamily
= 0;
187 } // namespace mozilla::dom