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 */