c6a670d16c143a01f61c59cc129b5af6a77ffc80
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMWindowCustom.cpp
1 /*
2  * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "JSDOMWindowCustom.h"
23
24 #include "DOMWindowIndexedDatabase.h"
25 #include "Frame.h"
26 #include "HTMLCollection.h"
27 #include "HTMLDocument.h"
28 #include "HTMLFrameOwnerElement.h"
29 #include "JSDOMBindingSecurity.h"
30 #include "JSDOMConvertNullable.h"
31 #include "JSDOMConvertNumbers.h"
32 #include "JSDOMConvertStrings.h"
33 #include "JSDOMWindowProxy.h"
34 #include "JSEvent.h"
35 #include "JSEventListener.h"
36 #include "JSHTMLAudioElement.h"
37 #include "JSHTMLCollection.h"
38 #include "JSHTMLOptionElement.h"
39 #include "JSIDBFactory.h"
40 #include "JSWorker.h"
41 #include "Location.h"
42 #include "RuntimeEnabledFeatures.h"
43 #include "ScheduledAction.h"
44 #include "Settings.h"
45 #include "WebCoreJSClientData.h"
46 #include <runtime/JSCInlines.h>
47 #include <runtime/Lookup.h>
48
49 #if ENABLE(USER_MESSAGE_HANDLERS)
50 #include "JSWebKitNamespace.h"
51 #endif
52
53
54 namespace WebCore {
55 using namespace JSC;
56
57 EncodedJSValue JSC_HOST_CALL jsDOMWindowInstanceFunctionShowModalDialog(ExecState*);
58
59 void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor)
60 {
61     if (Frame* frame = wrapped().frame())
62         visitor.addOpaqueRoot(frame);
63     
64     // Normally JSEventTargetCustom.cpp's JSEventTarget::visitAdditionalChildren() would call this. But
65     // even though DOMWindow is an EventTarget, JSDOMWindow does not subclass JSEventTarget, so we need
66     // to do this here.
67     wrapped().visitJSEventListeners(visitor);
68 }
69
70 #if ENABLE(USER_MESSAGE_HANDLERS)
71 static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValue, PropertyName)
72 {
73     VM& vm = exec->vm();
74     JSDOMWindow* castedThis = toJSDOMWindow(vm, JSValue::decode(thisValue));
75     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped()))
76         return JSValue::encode(jsUndefined());
77     return JSValue::encode(toJS(exec, castedThis->globalObject(), castedThis->wrapped().webkitNamespace()));
78 }
79 #endif
80
81 static bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMWindow* thisObject, Frame* frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot, const String& errorMessage)
82 {
83     VM& vm = exec->vm();
84     auto scope = DECLARE_THROW_SCOPE(vm);
85
86     auto& builtinNames = static_cast<JSVMClientData*>(vm.clientData)->builtinNames();
87
88     // We don't want any properties other than "close" and "closed" on a frameless window
89     // (i.e. one whose page got closed, or whose iframe got removed).
90     // FIXME: This handling for frameless windows duplicates similar behaviour for cross-origin
91     // access below; we should try to find a way to merge the two.
92     if (!frame) {
93         if (propertyName == builtinNames.closedPublicName()) {
94             slot.setCustom(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, jsDOMWindowClosed);
95             return true;
96         }
97         if (propertyName == builtinNames.closePublicName()) {
98             slot.setCustom(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>);
99             return true;
100         }
101
102         // FIXME: We should have a message here that explains why the property access/function call was
103         // not allowed. 
104         slot.setUndefined();
105         return true;
106     }
107
108     // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
109     if (propertyName == vm.propertyNames->toStringTagSymbol || propertyName == vm.propertyNames->hasInstanceSymbol || propertyName == vm.propertyNames->isConcatSpreadableSymbol) {
110         slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum, jsUndefined());
111         return true;
112     }
113
114     // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL).
115     // Always provide the original function, on a fresh uncached function object.
116     if (propertyName == builtinNames.blurPublicName()) {
117         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionBlur, 0>);
118         return true;
119     }
120     if (propertyName == builtinNames.closePublicName()) {
121         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>);
122         return true;
123     }
124     if (propertyName == builtinNames.focusPublicName()) {
125         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionFocus, 0>);
126         return true;
127     }
128     if (propertyName == builtinNames.postMessagePublicName()) {
129         slot.setCustom(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionPostMessage, 2>);
130         return true;
131     }
132
133     // When accessing cross-origin known Window properties, we always use the original property getter,
134     // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's
135     // behavior.
136     if (auto* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName)) {
137         // Only allow access to these specific properties.
138         if (propertyName == builtinNames.locationPublicName()
139             || propertyName == builtinNames.closedPublicName()
140             || propertyName == vm.propertyNames->length
141             || propertyName == builtinNames.selfPublicName()
142             || propertyName == builtinNames.windowPublicName()
143             || propertyName == builtinNames.framesPublicName()
144             || propertyName == builtinNames.openerPublicName()
145             || propertyName == builtinNames.parentPublicName()
146             || propertyName == builtinNames.topPublicName()) {
147             bool shouldExposeSetter = propertyName == builtinNames.locationPublicName();
148             CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, entry->propertyGetter(), shouldExposeSetter ? entry->propertyPutter() : nullptr);
149             slot.setCustomGetterSetter(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DontEnum), customGetterSetter);
150             return true;
151         }
152
153         // For any other entries in the static property table, deny access. (Early return also prevents
154         // named getter from returning frames with matching names - this seems a little questionable, see
155         // FIXME comment on prototype search below.)
156         throwSecurityError(*exec, scope, errorMessage);
157         slot.setUndefined();
158         return false;
159     }
160
161     // Check for child frames by name before built-in properties to match Mozilla. This does
162     // not match IE, but some sites end up naming frames things that conflict with window
163     // properties that are in Moz but not IE. Since we have some of these, we have to do it
164     // the Moz way.
165     if (auto* scopedChild = frame->tree().scopedChild(propertyNameToAtomicString(propertyName))) {
166         slot.setValue(thisObject, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, toJS(exec, scopedChild->document()->domWindow()));
167         return true;
168     }
169
170     throwSecurityError(*exec, scope, errorMessage);
171     slot.setUndefined();
172     return false;
173 }
174
175 // Property access sequence is:
176 // (1) indexed properties,
177 // (2) regular own properties,
178 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
179 bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot)
180 {
181     // (1) First, indexed properties.
182     // Hand off all indexed access to getOwnPropertySlotByIndex, which supports the indexed getter.
183     if (std::optional<unsigned> index = parseIndex(propertyName))
184         return getOwnPropertySlotByIndex(object, state, index.value(), slot);
185
186     auto* thisObject = jsCast<JSDOMWindow*>(object);
187     auto* frame = thisObject->wrapped().frame();
188
189     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
190     String errorMessage;
191     if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
192         return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, propertyName, slot, errorMessage);
193     
194     // FIXME: this need more explanation.
195     // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?)
196     slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints);
197
198     // (2) Regular own properties.
199     PropertySlot slotCopy = slot;
200     if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) {
201         // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value.
202         bool isShowModalDialogAndShouldHide = propertyName == static_cast<JSVMClientData*>(state->vm().clientData)->builtinNames().showModalDialogPublicName()
203             && !DOMWindow::canShowModalDialog(*frame)
204             && slot.isValue() && isHostFunction(slot.getValue(state, propertyName), jsDOMWindowInstanceFunctionShowModalDialog);
205         // Unless we're in the showModalDialog special case, we're done.
206         if (!isShowModalDialogAndShouldHide)
207             return true;
208         slot = slotCopy;
209     }
210
211 #if ENABLE(USER_MESSAGE_HANDLERS)
212     if (propertyName == static_cast<JSVMClientData*>(state->vm().clientData)->builtinNames().webkitPublicName() && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) {
213         slot.setCacheableCustom(thisObject, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly, jsDOMWindowWebKit);
214         return true;
215     }
216 #endif
217
218     return false;
219 }
220
221 // Property access sequence is:
222 // (1) indexed properties,
223 // (2) regular own properties,
224 // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO).
225 bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot)
226 {
227     auto* thisObject = jsCast<JSDOMWindow*>(object);
228     auto* frame = thisObject->wrapped().frame();
229
230     // Indexed getters take precendence over regular properties, so caching would be invalid.
231     slot.disableCaching();
232
233     // (1) First, indexed properties.
234     // These are also allowed cross-orgin, so come before the access check.
235     if (frame && index < frame->tree().scopedChildCount()) {
236         slot.setValue(thisObject, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontEnum), toJS(state, frame->tree().scopedChild(index)->document()->domWindow()));
237         return true;
238     }
239
240     // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess.
241     String errorMessage;
242     if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
243         return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, Identifier::from(state, index), slot, errorMessage);
244
245     // (2) Regular own properties.
246     return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot);
247 }
248
249 bool JSDOMWindow::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
250 {
251     VM& vm = state->vm();
252     auto scope = DECLARE_THROW_SCOPE(vm);
253
254     auto* thisObject = jsCast<JSDOMWindow*>(cell);
255     if (!thisObject->wrapped().frame())
256         return false;
257
258     String errorMessage;
259     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) {
260         // We only allow setting "location" attribute cross-origin.
261         if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName()) {
262             bool putResult = false;
263             if (lookupPut(state, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult))
264                 return putResult;
265             return false;
266         }
267         throwSecurityError(*state, scope, errorMessage);
268         return false;
269     }
270
271     return Base::put(thisObject, state, propertyName, value, slot);
272 }
273
274 bool JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow)
275 {
276     auto* thisObject = jsCast<JSDOMWindow*>(cell);
277     if (!thisObject->wrapped().frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped()))
278         return false;
279     
280     return Base::putByIndex(thisObject, exec, index, value, shouldThrow);
281 }
282
283 bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
284 {
285     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
286     // Only allow deleting properties by frames in the same origin.
287     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
288         return false;
289     return Base::deleteProperty(thisObject, exec, propertyName);
290 }
291
292 bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
293 {
294     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
295     // Only allow deleting properties by frames in the same origin.
296     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
297         return false;
298     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
299 }
300
301 // https://html.spec.whatwg.org/#crossoriginproperties-(-o-)
302 static void addCrossOriginWindowPropertyNames(VM& vm, PropertyNameArray& propertyNames)
303 {
304     static const Identifier* const properties[] = {
305         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().blurPublicName(),
306         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().closePublicName(),
307         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().closedPublicName(),
308         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().focusPublicName(),
309         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().framesPublicName(),
310         &vm.propertyNames->length,
311         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName(),
312         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().openerPublicName(),
313         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().parentPublicName(),
314         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().postMessagePublicName(),
315         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().selfPublicName(),
316         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().topPublicName(),
317         &static_cast<JSVMClientData*>(vm.clientData)->builtinNames().windowPublicName()
318     };
319     for (auto* property : properties)
320         propertyNames.add(*property);
321 }
322
323 static void addScopedChildrenIndexes(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames)
324 {
325     auto* document = window.document();
326     if (!document)
327         return;
328
329     auto* frame = document->frame();
330     if (!frame)
331         return;
332
333     unsigned scopedChildCount = frame->tree().scopedChildCount();
334     for (unsigned i = 0; i < scopedChildCount; ++i)
335         propertyNames.add(Identifier::from(&state, i));
336 }
337
338 // https://html.spec.whatwg.org/#crossoriginownpropertykeys-(-o-)
339 static void addCrossOriginWindowOwnPropertyNames(ExecState& state, PropertyNameArray& propertyNames)
340 {
341     VM& vm = state.vm();
342     addCrossOriginWindowPropertyNames(vm, propertyNames);
343
344     propertyNames.add(vm.propertyNames->toStringTagSymbol);
345     propertyNames.add(vm.propertyNames->hasInstanceSymbol);
346     propertyNames.add(vm.propertyNames->isConcatSpreadableSymbol);
347 }
348
349 // https://html.spec.whatwg.org/#windowproxy-ownpropertykeys
350 void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
351 {
352     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
353
354     if (mode.includeDontEnumProperties())
355         addScopedChildrenIndexes(*exec, thisObject->wrapped(), propertyNames);
356
357     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) {
358         if (mode.includeDontEnumProperties())
359             addCrossOriginWindowOwnPropertyNames(*exec, propertyNames);
360         return;
361     }
362     Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
363 }
364
365 bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow)
366 {
367     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
368     // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced.
369     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
370         return false;
371
372     // Don't allow shadowing location using accessor properties.
373     if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location"))
374         return false;
375
376     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
377 }
378
379 JSValue JSDOMWindow::getPrototype(JSObject* object, ExecState* exec)
380 {
381     JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
382     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
383         return jsNull();
384
385     return Base::getPrototype(object, exec);
386 }
387
388 bool JSDOMWindow::preventExtensions(JSObject*, ExecState* exec)
389 {
390     auto scope = DECLARE_THROW_SCOPE(exec->vm());
391
392     throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object"));
393     return false;
394 }
395
396 String JSDOMWindow::toStringName(const JSObject* object, ExecState* exec)
397 {
398     auto* thisObject = jsCast<const JSDOMWindow*>(object);
399     if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError))
400         return ASCIILiteral("Object");
401     return ASCIILiteral("Window");
402 }
403
404 // Custom Attributes
405
406 JSValue JSDOMWindow::event(ExecState& state) const
407 {
408     Event* event = currentEvent();
409     if (!event)
410         return jsUndefined();
411     return toJS(&state, const_cast<JSDOMWindow*>(this), event);
412 }
413
414 // Custom functions
415
416 class DialogHandler {
417 public:
418     explicit DialogHandler(ExecState& exec)
419         : m_exec(exec)
420     {
421     }
422
423     void dialogCreated(DOMWindow&);
424     JSValue returnValue() const;
425
426 private:
427     ExecState& m_exec;
428     RefPtr<Frame> m_frame;
429 };
430
431 inline void DialogHandler::dialogCreated(DOMWindow& dialog)
432 {
433     m_frame = dialog.frame();
434     
435     // FIXME: This looks like a leak between the normal world and an isolated
436     //        world if dialogArguments comes from an isolated world.
437     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
438     if (JSValue dialogArguments = m_exec.argument(1))
439         globalObject->putDirect(m_exec.vm(), Identifier::fromString(&m_exec, "dialogArguments"), dialogArguments);
440 }
441
442 inline JSValue DialogHandler::returnValue() const
443 {
444     JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm()));
445     if (!globalObject)
446         return jsUndefined();
447     Identifier identifier = Identifier::fromString(&m_exec, "returnValue");
448     PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get);
449     if (!JSGlobalObject::getOwnPropertySlot(globalObject, &m_exec, identifier, slot))
450         return jsUndefined();
451     return slot.getValue(&m_exec, identifier);
452 }
453
454 JSValue JSDOMWindow::showModalDialog(ExecState& state)
455 {
456     VM& vm = state.vm();
457     auto scope = DECLARE_THROW_SCOPE(vm);
458
459     if (UNLIKELY(state.argumentCount() < 1))
460         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
461
462     String urlString = convert<IDLNullable<IDLDOMString>>(state, state.argument(0));
463     RETURN_IF_EXCEPTION(scope, JSValue());
464     String dialogFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2));
465     RETURN_IF_EXCEPTION(scope, JSValue());
466
467     DialogHandler handler(state);
468
469     wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(state), firstDOMWindow(state), [&handler](DOMWindow& dialog) {
470         handler.dialogCreated(dialog);
471     });
472
473     return handler.returnValue();
474 }
475
476 DOMWindow* JSDOMWindow::toWrapped(VM& vm, JSValue value)
477 {
478     if (!value.isObject())
479         return nullptr;
480     JSObject* object = asObject(value);
481     if (object->inherits(vm, JSDOMWindow::info()))
482         return &jsCast<JSDOMWindow*>(object)->wrapped();
483     if (object->inherits(vm, JSDOMWindowProxy::info()))
484         return &jsCast<JSDOMWindowProxy*>(object)->wrapped();
485     return nullptr;
486 }
487
488 } // namespace WebCore