diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /dom/bindings/RemoteObjectProxy.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream/115.8.0esr.tar.xz firefox-esr-upstream/115.8.0esr.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/bindings/RemoteObjectProxy.cpp')
-rw-r--r-- | dom/bindings/RemoteObjectProxy.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/dom/bindings/RemoteObjectProxy.cpp b/dom/bindings/RemoteObjectProxy.cpp new file mode 100644 index 0000000000..c17686627f --- /dev/null +++ b/dom/bindings/RemoteObjectProxy.cpp @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoteObjectProxy.h" +#include "AccessCheck.h" +#include "jsfriendapi.h" +#include "js/Object.h" // JS::GetClass +#include "xpcprivate.h" + +namespace mozilla::dom { + +bool RemoteObjectProxyBase::getOwnPropertyDescriptor( + JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::MutableHandle<Maybe<JS::PropertyDescriptor>> aDesc) const { + bool ok = CrossOriginGetOwnPropertyHelper(aCx, aProxy, aId, aDesc); + if (!ok || aDesc.isSome()) { + return ok; + } + + return CrossOriginPropertyFallback(aCx, aProxy, aId, aDesc); +} + +bool RemoteObjectProxyBase::defineProperty( + JSContext* aCx, JS::Handle<JSObject*> aProxy, JS::Handle<jsid> aId, + JS::Handle<JS::PropertyDescriptor> aDesc, + JS::ObjectOpResult& aResult) const { + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-defineownproperty + // step 3 and + // https://html.spec.whatwg.org/multipage/browsers.html#location-defineownproperty + // step 2 + return ReportCrossOriginDenial(aCx, aId, "define"_ns); +} + +bool RemoteObjectProxyBase::ownPropertyKeys( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const { + // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-) + // step 2 and + // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-) + JS::Rooted<JSObject*> holder(aCx); + if (!EnsureHolder(aCx, aProxy, &holder) || + !js::GetPropertyKeys(aCx, holder, + JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, + aProps)) { + return false; + } + + // https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-) + // step 3 and 4 + return xpc::AppendCrossOriginWhitelistedPropNames(aCx, aProps); +} + +bool RemoteObjectProxyBase::delete_(JSContext* aCx, + JS::Handle<JSObject*> aProxy, + JS::Handle<jsid> aId, + JS::ObjectOpResult& aResult) const { + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-delete + // step 3 and + // https://html.spec.whatwg.org/multipage/browsers.html#location-delete step 2 + return ReportCrossOriginDenial(aCx, aId, "delete"_ns); +} + +bool RemoteObjectProxyBase::getPrototypeIfOrdinary( + JSContext* aCx, JS::Handle<JSObject*> aProxy, bool* aIsOrdinary, + JS::MutableHandle<JSObject*> aProtop) const { + // WindowProxy's and Location's [[GetPrototypeOf]] traps aren't the ordinary + // definition: + // + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof + // https://html.spec.whatwg.org/multipage/browsers.html#location-getprototypeof + // + // We nonetheless can implement it with a static [[Prototype]], because the + // [[GetPrototypeOf]] trap should always return null. + *aIsOrdinary = true; + aProtop.set(nullptr); + return true; +} + +bool RemoteObjectProxyBase::preventExtensions( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::ObjectOpResult& aResult) const { + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-preventextensions + // and + // https://html.spec.whatwg.org/multipage/browsers.html#location-preventextensions + return aResult.failCantPreventExtensions(); +} + +bool RemoteObjectProxyBase::isExtensible(JSContext* aCx, + JS::Handle<JSObject*> aProxy, + bool* aExtensible) const { + // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-isextensible + // and + // https://html.spec.whatwg.org/multipage/browsers.html#location-isextensible + *aExtensible = true; + return true; +} + +bool RemoteObjectProxyBase::get(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::Handle<JS::Value> aReceiver, + JS::Handle<jsid> aId, + JS::MutableHandle<JS::Value> aVp) const { + return CrossOriginGet(aCx, aProxy, aReceiver, aId, aVp); +} + +bool RemoteObjectProxyBase::set(JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::Handle<jsid> aId, + JS::Handle<JS::Value> aValue, + JS::Handle<JS::Value> aReceiver, + JS::ObjectOpResult& aResult) const { + return CrossOriginSet(aCx, aProxy, aId, aValue, aReceiver, aResult); +} + +bool RemoteObjectProxyBase::getOwnEnumerablePropertyKeys( + JSContext* aCx, JS::Handle<JSObject*> aProxy, + JS::MutableHandleVector<jsid> aProps) const { + return true; +} + +const char* RemoteObjectProxyBase::className( + JSContext* aCx, JS::Handle<JSObject*> aProxy) const { + MOZ_ASSERT(js::IsProxy(aProxy)); + + return "Object"; +} + +void RemoteObjectProxyBase::GetOrCreateProxyObject( + JSContext* aCx, void* aNative, const JSClass* aClasp, + JS::Handle<JSObject*> aTransplantTo, JS::MutableHandle<JSObject*> aProxy, + bool& aNewObjectCreated) const { + xpc::CompartmentPrivate* priv = + xpc::CompartmentPrivate::Get(JS::CurrentGlobalOrNull(aCx)); + xpc::CompartmentPrivate::RemoteProxyMap& map = priv->GetRemoteProxyMap(); + if (auto result = map.lookup(aNative)) { + MOZ_ASSERT(!aTransplantTo, + "No existing value allowed if we're doing a transplant"); + + aProxy.set(result->value()); + + // During a transplant, we put an object that is temporarily not a + // proxy object into the map. Make sure that we don't return one of + // these objects in the middle of a transplant. + MOZ_RELEASE_ASSERT(JS::GetClass(aProxy) == aClasp); + + return; + } + + js::ProxyOptions options; + options.setClass(aClasp); + JS::Rooted<JS::Value> native(aCx, JS::PrivateValue(aNative)); + JS::Rooted<JSObject*> obj( + aCx, js::NewProxyObject(aCx, this, native, nullptr, options)); + if (!obj) { + return; + } + + bool success; + if (!JS_SetImmutablePrototype(aCx, obj, &success)) { + return; + } + MOZ_ASSERT(success); + + aNewObjectCreated = true; + + // If we're transplanting onto an object, we want to make sure that it does + // not have the same class as aClasp to ensure that the release assert earlier + // in this function will actually fire if we try to return a proxy object in + // the middle of a transplant. + MOZ_ASSERT_IF(aTransplantTo, JS::GetClass(aTransplantTo) != aClasp); + + if (!map.put(aNative, aTransplantTo ? aTransplantTo : obj)) { + return; + } + + aProxy.set(obj); +} + +const char RemoteObjectProxyBase::sCrossOriginProxyFamily = 0; + +} // namespace mozilla::dom |