diff options
Diffstat (limited to 'dom/base/MaybeCrossOriginObject.h')
-rw-r--r-- | dom/base/MaybeCrossOriginObject.h | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/dom/base/MaybeCrossOriginObject.h b/dom/base/MaybeCrossOriginObject.h new file mode 100644 index 0000000000..e6fe70078d --- /dev/null +++ b/dom/base/MaybeCrossOriginObject.h @@ -0,0 +1,360 @@ +/* -*- 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/. */ + +#ifndef mozilla_dom_MaybeCrossOriginObject_h +#define mozilla_dom_MaybeCrossOriginObject_h + +/** + * Shared infrastructure for WindowProxy and Location objects. These + * are the objects that can be accessed cross-origin in the HTML + * specification. + * + * This class can be inherited from by the relevant proxy handlers to + * help implement spec algorithms. + * + * The algorithms this class implements come from + * <https://html.spec.whatwg.org/multipage/browsers.html#shared-abstract-operations>, + * <https://html.spec.whatwg.org/multipage/window-object.html#the-windowproxy-exotic-object>, + * and + * <https://html.spec.whatwg.org/multipage/history.html#the-location-interface>. + * + * The class is templated on its base so we can directly implement the things + * that should have identical implementations for WindowProxy and Location. The + * templating is needed because WindowProxy needs to be a wrapper and Location + * shouldn't be one. + */ + +#include "js/Class.h" +#include "js/TypeDecls.h" +#include "nsStringFwd.h" + +namespace mozilla { +namespace dom { + +/** + * "mAttributes" and "mMethods" are the cross-origin attributes and methods we + * care about, which should get defined on holders. + * + * "mChromeOnlyAttributes" and "mChromeOnlyMethods" are the cross-origin + * attributes and methods we care about, which should get defined on holders + * for the chrome realm, in addition to the properties that are in + * "mAttributes" and "mMethods". + */ +struct CrossOriginProperties { + const JSPropertySpec* mAttributes; + const JSFunctionSpec* mMethods; + const JSPropertySpec* mChromeOnlyAttributes; + const JSFunctionSpec* mChromeOnlyMethods; +}; + +// Methods that MaybeCrossOriginObject wants that do not depend on the "Base" +// template parameter. We can avoid having multiple instantiations of them by +// pulling them out into this helper class. +class MaybeCrossOriginObjectMixins { + public: + /** + * Implementation of + * <https://html.spec.whatwg.org/multipage/browsers.html#isplatformobjectsameorigin-(-o-)>. + * "cx" and "obj" may or may not be same-compartment and even when + * same-compartment may not be same-Realm. "obj" can be a WindowProxy, a + * Window, or a Location. + */ + static bool IsPlatformObjectSameOrigin(JSContext* cx, JSObject* obj); + + protected: + /** + * Implementation of + * <https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)>. + * + * "cx" and "obj" are expected to be different-Realm here, and may be + * different-compartment. "obj" can be a "WindowProxy" or a "Location" or a + * cross-process proxy for one of those. + */ + bool CrossOriginGetOwnPropertyHelper( + JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, + JS::MutableHandle<JS::PropertyDescriptor> desc) const; + + /** + * Implementation of + * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginpropertyfallback-(-p-)>. + * + * This should be called at the end of getOwnPropertyDescriptor + * methods in the cross-origin case. + * + * "cx" and "obj" are expected to be different-Realm here, and may + * be different-compartment. "obj" can be a "WindowProxy" or a + * "Location" or a cross-process proxy for one of those. + */ + static bool CrossOriginPropertyFallback( + JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id, + JS::MutableHandle<JS::PropertyDescriptor> desc); + + /** + * Implementation of + * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginget-(-o,-p,-receiver-)>. + * + * "cx" and "obj" are expected to be different-Realm here and may be + * different-compartment. "obj" can be a "WindowProxy" or a + * "Location" or a cross-process proxy for one of those. + * + * "receiver" will be in the compartment of "cx". The return value will + * be in the compartment of "cx". + */ + static bool CrossOriginGet(JSContext* cx, JS::Handle<JSObject*> obj, + JS::Handle<JS::Value> receiver, + JS::Handle<jsid> id, + JS::MutableHandle<JS::Value> vp); + + /** + * Implementation of + * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginset-(-o,-p,-v,-receiver-)>. + * + * "cx" and "obj" are expected to be different-Realm here and may be + * different-compartment. "obj" can be a "WindowProxy" or a + * "Location" or a cross-process proxy for one of those. + * + * "receiver" and "v" will be in the compartment of "cx". + */ + static bool CrossOriginSet(JSContext* cx, JS::Handle<JSObject*> obj, + JS::Handle<jsid> id, JS::Handle<JS::Value> v, + JS::Handle<JS::Value> receiver, + JS::ObjectOpResult& result); + + /** + * Utility method to ensure a holder for cross-origin properties for the + * current global of the JSContext. + * + * When this is called, "cx" and "obj" are _always_ different-Realm, because + * this is only used in cross-origin situations. The "holder" return value is + * always in the Realm of "cx". + * + * "obj" is the object which has space to store the collection of holders in + * the given slot. + * + * "properties" are the cross-origin attributes and methods we care about, + * which should get defined on holders. + */ + static bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> obj, + size_t slot, const CrossOriginProperties& properties, + JS::MutableHandle<JSObject*> holder); + + /** + * Ensures we have a holder object for the current Realm. When this is + * called, "obj" is guaranteed to not be same-Realm with "cx", because this + * is only used for cross-origin cases. + * + * Subclasses are expected to implement this by calling our static + * EnsureHolder with the appropriate arguments. + */ + virtual bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::MutableHandle<JSObject*> holder) const = 0; + + /** + * Report a cross-origin denial for a property named by aId. Always + * returns false, so it can be used as "return + * ReportCrossOriginDenial(...);". + */ + static bool ReportCrossOriginDenial(JSContext* aCx, JS::Handle<jsid> aId, + const nsACString& aAccessType); +}; + +// A proxy handler for objects that may be cross-origin objects. Whether they +// actually _are_ cross-origin objects can change dynamically if document.domain +// is set. +template <typename Base> +class MaybeCrossOriginObject : public Base, + public MaybeCrossOriginObjectMixins { + protected: + template <typename... Args> + constexpr MaybeCrossOriginObject(Args&&... aArgs) + : Base(std::forward<Args>(aArgs)...) {} + + /** + * Implementation of [[GetPrototypeOf]] as defined in + * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getprototypeof> + * and + * <https://html.spec.whatwg.org/multipage/history.html#location-getprototypeof>. + * + * Our prototype-storage model looks quite different from the spec's, so we + * need to implement some hooks that don't directly map to the spec. + * + * "proxy" is the WindowProxy or Location involved. It may or may not be + * same-compartment with cx. + * + * "protop" is the prototype value (possibly null). It is guaranteed to be + * same-compartment with cx after this function returns successfully. + */ + bool getPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::MutableHandle<JSObject*> protop) const final; + + /** + * Hook for doing the OrdinaryGetPrototypeOf bits that [[GetPrototypeOf]] does + * in the spec. Location and WindowProxy store that information somewhat + * differently. + * + * The prototype should come from the Realm of "cx". + */ + virtual JSObject* getSameOriginPrototype(JSContext* cx) const = 0; + + /** + * Implementation of [[SetPrototypeOf]] as defined in + * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-setprototypeof> + * and + * <https://html.spec.whatwg.org/multipage/history.html#location-setprototypeof>. + * + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with "cx". + * + * "proto" is the new prototype object (possibly null). It must be + * same-compartment with "cx". + */ + bool setPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::Handle<JSObject*> proto, + JS::ObjectOpResult& result) const final; + + /** + * Our non-standard getPrototypeIfOrdinary hook. + */ + bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy, + bool* isOrdinary, + JS::MutableHandle<JSObject*> protop) const final; + + /** + * Our non-standard setImmutablePrototype hook. + */ + bool setImmutablePrototype(JSContext* cx, JS::Handle<JSObject*> proxy, + bool* succeeded) const final; + + /** + * Implementation of [[IsExtensible]] as defined in + * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-isextensible> + * and + * <https://html.spec.whatwg.org/multipage/history.html#location-isextensible>. + */ + bool isExtensible(JSContext* cx, JS::Handle<JSObject*> proxy, + bool* extensible) const final; + + /** + * Implementation of [[PreventExtensions]] as defined in + * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-preventextensions> + * and + * <https://html.spec.whatwg.org/multipage/history.html#location-preventextensions>. + */ + bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::ObjectOpResult& result) const final; + + /** + * Implementation of [[GetOwnProperty]] is completely delegated to subclasses. + * + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with cx. + */ + bool getOwnPropertyDescriptor( + JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, + JS::MutableHandle<JS::PropertyDescriptor> desc) const override = 0; + + /** + * Implementation of [[DefineOwnProperty]] as defined in + * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-defineownproperty> + * and + * <https://html.spec.whatwg.org/multipage/history.html#location-defineownproperty>. + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with cx. + * + */ + bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::Handle<jsid> id, + JS::Handle<JS::PropertyDescriptor> desc, + JS::ObjectOpResult& result) const final; + + /** + * Some of our base classes define _another_ virtual defineProperty, and we + * get overloaded-virtual warnings as a result due to us hiding it, if we + * don't pull it in here. + */ + using Base::defineProperty; + + /** + * Hook for handling the same-origin case in defineProperty. + * + * "proxy" is the WindowProxy or Location object involved. It will be + * same-compartment with cx. + * + * "desc" is a the descriptor being defined. It will be same-compartment with + * cx. + */ + virtual bool definePropertySameOrigin(JSContext* cx, + JS::Handle<JSObject*> proxy, + JS::Handle<jsid> id, + JS::Handle<JS::PropertyDescriptor> desc, + JS::ObjectOpResult& result) const = 0; + + /** + * Implementation of [[Get]] is completely delegated to subclasses. + * + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with "cx". + * + * "receiver" is the receiver ("this") for the get. It will be + * same-compartment with "cx" + * + * "vp" is the return value. It will be same-compartment with "cx". + */ + bool get(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::Handle<JS::Value> receiver, JS::Handle<jsid> id, + JS::MutableHandle<JS::Value> vp) const override = 0; + + /** + * Implementation of [[Set]] is completely delegated to subclasses. + * + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with "cx". + * + * "v" is the value being set. It will be same-compartment with "cx". + * + * "receiver" is the receiver ("this") for the set. It will be + * same-compartment with "cx". + */ + bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, + JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver, + JS::ObjectOpResult& result) const override = 0; + + /** + * Implementation of [[Delete]] is completely delegated to subclasses. + * + * "proxy" is the WindowProxy or Location object involved. It may or may not + * be same-compartment with "cx". + */ + bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, + JS::ObjectOpResult& result) const override = 0; + + /** + * Spidermonkey-internal hook for enumerating objects. + */ + bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::MutableHandleVector<jsid> props) const final; + + /** + * Spidermonkey-internal hook used for instanceof. We need to override this + * because otherwise we can end up doing instanceof work in the wrong + * compartment. + */ + bool hasInstance(JSContext* cx, JS::Handle<JSObject*> proxy, + JS::MutableHandle<JS::Value> v, bool* bp) const final; + + /** + * Spidermonkey-internal hook used by Object.prototype.toString. Subclasses + * need to implement this, because we don't know what className they want. + * Except in the cross-origin case, when we could maybe handle it... + */ + const char* className(JSContext* cx, + JS::Handle<JSObject*> proxy) const override = 0; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_MaybeCrossOriginObject_h */ |