tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MaybeCrossOriginObject.h (14264B)


      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/. */
      6 
      7 #ifndef mozilla_dom_MaybeCrossOriginObject_h
      8 #define mozilla_dom_MaybeCrossOriginObject_h
      9 
     10 /**
     11 * Shared infrastructure for WindowProxy and Location objects.  These
     12 * are the objects that can be accessed cross-origin in the HTML
     13 * specification.
     14 *
     15 * This class can be inherited from by the relevant proxy handlers to
     16 * help implement spec algorithms.
     17 *
     18 * The algorithms this class implements come from
     19 * <https://html.spec.whatwg.org/multipage/browsers.html#shared-abstract-operations>,
     20 * <https://html.spec.whatwg.org/multipage/window-object.html#the-windowproxy-exotic-object>,
     21 * and
     22 * <https://html.spec.whatwg.org/multipage/history.html#the-location-interface>.
     23 *
     24 * The class is templated on its base so we can directly implement the things
     25 * that should have identical implementations for WindowProxy and Location.  The
     26 * templating is needed because WindowProxy needs to be a wrapper and Location
     27 * shouldn't be one.
     28 */
     29 
     30 #include "js/Class.h"
     31 #include "js/TypeDecls.h"
     32 #include "mozilla/Maybe.h"
     33 #include "nsStringFwd.h"
     34 
     35 namespace mozilla::dom {
     36 
     37 /**
     38 * "mAttributes" and "mMethods" are the cross-origin attributes and methods we
     39 * care about, which should get defined on holders.
     40 *
     41 * "mChromeOnlyAttributes" and "mChromeOnlyMethods" are the cross-origin
     42 * attributes and methods we care about, which should get defined on holders
     43 * for the chrome realm, in addition to the properties that are in
     44 * "mAttributes" and "mMethods".
     45 */
     46 struct CrossOriginProperties {
     47  const JSPropertySpec* mAttributes;
     48  const JSFunctionSpec* mMethods;
     49  const JSPropertySpec* mChromeOnlyAttributes;
     50  const JSFunctionSpec* mChromeOnlyMethods;
     51 };
     52 
     53 // Methods that MaybeCrossOriginObject wants that do not depend on the "Base"
     54 // template parameter.  We can avoid having multiple instantiations of them by
     55 // pulling them out into this helper class.
     56 class MaybeCrossOriginObjectMixins {
     57 public:
     58  /**
     59   * Implementation of
     60   * <https://html.spec.whatwg.org/multipage/browsers.html#isplatformobjectsameorigin-(-o-)>.
     61   * "cx" and "obj" may or may not be same-compartment and even when
     62   * same-compartment may not be same-Realm.  "obj" can be a WindowProxy, a
     63   * Window, or a Location.
     64   */
     65  static bool IsPlatformObjectSameOrigin(JSContext* cx, JSObject* obj);
     66 
     67 protected:
     68  /**
     69   * Implementation of
     70   * <https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)>.
     71   *
     72   * "cx" and "obj" are expected to be different-Realm here, and may be
     73   * different-compartment.  "obj" can be a "WindowProxy" or a "Location" or a
     74   * cross-process proxy for one of those.
     75   */
     76  bool CrossOriginGetOwnPropertyHelper(
     77      JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
     78      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const;
     79 
     80  /**
     81   * Implementation of
     82   * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginpropertyfallback-(-p-)>.
     83   *
     84   * This should be called at the end of getOwnPropertyDescriptor
     85   * methods in the cross-origin case.
     86   *
     87   * "cx" and "obj" are expected to be different-Realm here, and may
     88   * be different-compartment.  "obj" can be a "WindowProxy" or a
     89   * "Location" or a cross-process proxy for one of those.
     90   */
     91  static bool CrossOriginPropertyFallback(
     92      JSContext* cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
     93      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc);
     94 
     95  /**
     96   * Implementation of
     97   * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginget-(-o,-p,-receiver-)>.
     98   *
     99   * "cx" and "obj" are expected to be different-Realm here and may be
    100   * different-compartment.  "obj" can be a "WindowProxy" or a
    101   * "Location" or a cross-process proxy for one of those.
    102   *
    103   * "receiver" will be in the compartment of "cx".  The return value will
    104   * be in the compartment of "cx".
    105   */
    106  static bool CrossOriginGet(JSContext* cx, JS::Handle<JSObject*> obj,
    107                             JS::Handle<JS::Value> receiver,
    108                             JS::Handle<jsid> id,
    109                             JS::MutableHandle<JS::Value> vp);
    110 
    111  /**
    112   * Implementation of
    113   * <https://html.spec.whatwg.org/multipage/browsers.html#crossoriginset-(-o,-p,-v,-receiver-)>.
    114   *
    115   * "cx" and "obj" are expected to be different-Realm here and may be
    116   * different-compartment.  "obj" can be a "WindowProxy" or a
    117   * "Location" or a cross-process proxy for one of those.
    118   *
    119   * "receiver" and "v" will be in the compartment of "cx".
    120   */
    121  static bool CrossOriginSet(JSContext* cx, JS::Handle<JSObject*> obj,
    122                             JS::Handle<jsid> id, JS::Handle<JS::Value> v,
    123                             JS::Handle<JS::Value> receiver,
    124                             JS::ObjectOpResult& result);
    125 
    126  /**
    127   * Utility method to ensure a holder for cross-origin properties for the
    128   * current global of the JSContext.
    129   *
    130   * When this is called, "cx" and "obj" are _always_ different-Realm, because
    131   * this is only used in cross-origin situations.  The "holder" return value is
    132   * always in the Realm of "cx".
    133   *
    134   * "obj" is the object which has space to store the collection of holders in
    135   * the given slot.
    136   *
    137   * "properties" are the cross-origin attributes and methods we care about,
    138   * which should get defined on holders.
    139   */
    140  static bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> obj,
    141                           size_t slot, const CrossOriginProperties& properties,
    142                           JS::MutableHandle<JSObject*> holder);
    143 
    144  /**
    145   * Ensures we have a holder object for the current Realm.  When this is
    146   * called, "obj" is guaranteed to not be same-Realm with "cx", because this
    147   * is only used for cross-origin cases.
    148   *
    149   * Subclasses are expected to implement this by calling our static
    150   * EnsureHolder with the appropriate arguments.
    151   */
    152  virtual bool EnsureHolder(JSContext* cx, JS::Handle<JSObject*> proxy,
    153                            JS::MutableHandle<JSObject*> holder) const = 0;
    154 
    155  /**
    156   * Report a cross-origin denial for a property named by aId.  Always
    157   * returns false, so it can be used as "return
    158   * ReportCrossOriginDenial(...);".
    159   */
    160  static bool ReportCrossOriginDenial(JSContext* aCx, JS::Handle<jsid> aId,
    161                                      const nsACString& aAccessType);
    162 };
    163 
    164 // A proxy handler for objects that may be cross-origin objects.  Whether they
    165 // actually _are_ cross-origin objects can change dynamically if document.domain
    166 // is set.
    167 template <typename Base>
    168 class MaybeCrossOriginObject : public Base,
    169                               public MaybeCrossOriginObjectMixins {
    170 protected:
    171  template <typename... Args>
    172  constexpr MaybeCrossOriginObject(Args&&... aArgs)
    173      : Base(std::forward<Args>(aArgs)...) {}
    174 
    175  /**
    176   * Implementation of [[GetPrototypeOf]] as defined in
    177   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-getprototypeof>
    178   * and
    179   * <https://html.spec.whatwg.org/multipage/history.html#location-getprototypeof>.
    180   *
    181   * Our prototype-storage model looks quite different from the spec's, so we
    182   * need to implement some hooks that don't directly map to the spec.
    183   *
    184   * "proxy" is the WindowProxy or Location involved.  It may or may not be
    185   * same-compartment with cx.
    186   *
    187   * "protop" is the prototype value (possibly null).  It is guaranteed to be
    188   * same-compartment with cx after this function returns successfully.
    189   */
    190  bool getPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    191                    JS::MutableHandle<JSObject*> protop) const final;
    192 
    193  /**
    194   * Hook for doing the OrdinaryGetPrototypeOf bits that [[GetPrototypeOf]] does
    195   * in the spec.  Location and WindowProxy store that information somewhat
    196   * differently.
    197   *
    198   * The prototype should come from the Realm of "cx".
    199   */
    200  virtual JSObject* getSameOriginPrototype(JSContext* cx) const = 0;
    201 
    202  /**
    203   * Implementation of [[SetPrototypeOf]] as defined in
    204   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-setprototypeof>
    205   * and
    206   * <https://html.spec.whatwg.org/multipage/history.html#location-setprototypeof>.
    207   *
    208   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    209   * be same-compartment with "cx".
    210   *
    211   * "proto" is the new prototype object (possibly null).  It must be
    212   * same-compartment with "cx".
    213   */
    214  bool setPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    215                    JS::Handle<JSObject*> proto,
    216                    JS::ObjectOpResult& result) const final;
    217 
    218  /**
    219   * Our non-standard getPrototypeIfOrdinary hook.
    220   */
    221  bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle<JSObject*> proxy,
    222                              bool* isOrdinary,
    223                              JS::MutableHandle<JSObject*> protop) const final;
    224 
    225  /**
    226   * Our non-standard setImmutablePrototype hook.
    227   */
    228  bool setImmutablePrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
    229                             bool* succeeded) const final;
    230 
    231  /**
    232   * Implementation of [[IsExtensible]] as defined in
    233   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-isextensible>
    234   * and
    235   * <https://html.spec.whatwg.org/multipage/history.html#location-isextensible>.
    236   */
    237  bool isExtensible(JSContext* cx, JS::Handle<JSObject*> proxy,
    238                    bool* extensible) const final;
    239 
    240  /**
    241   * Implementation of [[PreventExtensions]] as defined in
    242   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-preventextensions>
    243   * and
    244   * <https://html.spec.whatwg.org/multipage/history.html#location-preventextensions>.
    245   */
    246  bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> proxy,
    247                         JS::ObjectOpResult& result) const final;
    248 
    249  /**
    250   * Implementation of [[GetOwnProperty]] is completely delegated to subclasses.
    251   *
    252   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    253   * be same-compartment with cx.
    254   */
    255  bool getOwnPropertyDescriptor(
    256      JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    257      JS::MutableHandle<Maybe<JS::PropertyDescriptor>> desc) const override = 0;
    258 
    259  /**
    260   * Implementation of [[DefineOwnProperty]] as defined in
    261   * <https://html.spec.whatwg.org/multipage/window-object.html#windowproxy-defineownproperty>
    262   * and
    263   * <https://html.spec.whatwg.org/multipage/history.html#location-defineownproperty>.
    264   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    265   * be same-compartment with cx.
    266   *
    267   */
    268  bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy,
    269                      JS::Handle<jsid> id,
    270                      JS::Handle<JS::PropertyDescriptor> desc,
    271                      JS::ObjectOpResult& result) const final;
    272 
    273  /**
    274   * Some of our base classes define _another_ virtual defineProperty, and we
    275   * get overloaded-virtual warnings as a result due to us hiding it, if we
    276   * don't pull it in here.
    277   */
    278  using Base::defineProperty;
    279 
    280  /**
    281   * Hook for handling the same-origin case in defineProperty.
    282   *
    283   * "proxy" is the WindowProxy or Location object involved.  It will be
    284   * same-compartment with cx.
    285   *
    286   * "desc" is a the descriptor being defined.  It will be same-compartment with
    287   * cx.
    288   */
    289  virtual bool definePropertySameOrigin(JSContext* cx,
    290                                        JS::Handle<JSObject*> proxy,
    291                                        JS::Handle<jsid> id,
    292                                        JS::Handle<JS::PropertyDescriptor> desc,
    293                                        JS::ObjectOpResult& result) const = 0;
    294 
    295  /**
    296   * Implementation of [[Get]] is completely delegated to subclasses.
    297   *
    298   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    299   * be same-compartment with "cx".
    300   *
    301   * "receiver" is the receiver ("this") for the get.  It will be
    302   * same-compartment with "cx"
    303   *
    304   * "vp" is the return value.  It will be same-compartment with "cx".
    305   */
    306  bool get(JSContext* cx, JS::Handle<JSObject*> proxy,
    307           JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
    308           JS::MutableHandle<JS::Value> vp) const override = 0;
    309 
    310  /**
    311   * Implementation of [[Set]] is completely delegated to subclasses.
    312   *
    313   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    314   * be same-compartment with "cx".
    315   *
    316   * "v" is the value being set.  It will be same-compartment with "cx".
    317   *
    318   * "receiver" is the receiver ("this") for the set.  It will be
    319   * same-compartment with "cx".
    320   */
    321  bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    322           JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
    323           JS::ObjectOpResult& result) const override = 0;
    324 
    325  /**
    326   * Implementation of [[Delete]] is completely delegated to subclasses.
    327   *
    328   * "proxy" is the WindowProxy or Location object involved.  It may or may not
    329   * be same-compartment with "cx".
    330   */
    331  bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
    332               JS::ObjectOpResult& result) const override = 0;
    333 
    334  /**
    335   * Spidermonkey-internal hook for enumerating objects.
    336   */
    337  bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
    338                 JS::MutableHandleVector<jsid> props) const final;
    339 
    340  // Cross origin objects should not participate in private fields.
    341  virtual bool throwOnPrivateField() const override { return true; }
    342 
    343  /**
    344   * Spidermonkey-internal hook used by Object.prototype.toString.  Subclasses
    345   * need to implement this, because we don't know what className they want.
    346   * Except in the cross-origin case, when we could maybe handle it...
    347   */
    348  const char* className(JSContext* cx,
    349                        JS::Handle<JSObject*> proxy) const override = 0;
    350 };
    351 
    352 }  // namespace mozilla::dom
    353 
    354 #endif /* mozilla_dom_MaybeCrossOriginObject_h */