Diff
Modified: trunk/LayoutTests/ChangeLog (205358 => 205359)
--- trunk/LayoutTests/ChangeLog 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/LayoutTests/ChangeLog 2016-09-02 19:10:12 UTC (rev 205359)
@@ -1,5 +1,23 @@
2016-09-02 Chris Dumez <[email protected]>
+ Object.preventExtensions() should throw cross-origin
+ https://bugs.webkit.org/show_bug.cgi?id=161486
+
+ Reviewed by Geoffrey Garen.
+
+ Add layout test coverage. We have a few failures in the same origin case
+ because we don't fully match the specification yet:
+ - Object.preventExtensions() should throw a TypeError. However, our
+ implementation currently does not throw if [[PreventExtensions]] returns
+ false.
+ - We do not ignore calls to Object.preventExtensions() for the Location
+ object yet because other browsers do not seem to either.
+
+ * http/tests/security/preventExtensions-window-location-expected.txt: Added.
+ * http/tests/security/preventExtensions-window-location.html: Added.
+
+2016-09-02 Chris Dumez <[email protected]>
+
Object.defineProperty() should throw cross-origin
https://bugs.webkit.org/show_bug.cgi?id=161460
Added: trunk/LayoutTests/http/tests/security/preventExtensions-window-location-expected.txt (0 => 205359)
--- trunk/LayoutTests/http/tests/security/preventExtensions-window-location-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/security/preventExtensions-window-location-expected.txt 2016-09-02 19:10:12 UTC (rev 205359)
@@ -0,0 +1,24 @@
+Test the behavior of Object.preventExtensions() for Window / Location.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+* Cross origin
+PASS Object.isExtensible(frames[0]) is true
+PASS Object.preventExtensions(frames[0]) threw exception SecurityError (DOM Exception 18): Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match..
+PASS Object.isExtensible(frames[0]) is true
+PASS Object.isExtensible(frames[0].location) is true
+PASS Object.preventExtensions(frames[0].location) threw exception SecurityError (DOM Exception 18): Blocked a frame with origin "http://127.0.0.1:8000" from accessing a frame with origin "http://localhost:8000". Protocols, domains, and ports must match..
+PASS Object.isExtensible(frames[0].location) is true
+
+* Same origin
+PASS Object.isExtensible(window) is true
+FAIL Object.preventExtensions(window) should throw a TypeError. Did not throw.
+PASS Object.isExtensible(window) is true
+PASS Object.isExtensible(window.location) is true
+FAIL Object.preventExtensions(window.location) should throw a TypeError. Did not throw.
+FAIL Object.isExtensible(window.location) should be true. Was false.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/http/tests/security/preventExtensions-window-location.html (0 => 205359)
--- trunk/LayoutTests/http/tests/security/preventExtensions-window-location.html (rev 0)
+++ trunk/LayoutTests/http/tests/security/preventExtensions-window-location.html 2016-09-02 19:10:12 UTC (rev 205359)
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<iframe src=""
+<script>
+description("Test the behavior of Object.preventExtensions() for Window / Location.");
+jsTestIsAsync = true;
+
+_onload_ = function() {
+ debug ("* Cross origin");
+ shouldBeTrue("Object.isExtensible(frames[0])");
+ shouldThrowErrorName("Object.preventExtensions(frames[0])", "SecurityError");
+ shouldBeTrue("Object.isExtensible(frames[0])");
+
+ shouldBeTrue("Object.isExtensible(frames[0].location)");
+ shouldThrowErrorName("Object.preventExtensions(frames[0].location)", "SecurityError");
+ shouldBeTrue("Object.isExtensible(frames[0].location)");
+
+ debug("");
+ debug("* Same origin");
+ shouldBeTrue("Object.isExtensible(window)");
+ shouldThrowErrorName("Object.preventExtensions(window)", "TypeError");
+ shouldBeTrue("Object.isExtensible(window)");
+
+ shouldBeTrue("Object.isExtensible(window.location)");
+ shouldThrowErrorName("Object.preventExtensions(window.location)", "TypeError");
+ shouldBeTrue("Object.isExtensible(window.location)");
+
+ finishJSTest();
+};
+</script>
+<script src=""
+</body>
+</html>
Modified: trunk/Source/_javascript_Core/ChangeLog (205358 => 205359)
--- trunk/Source/_javascript_Core/ChangeLog 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-09-02 19:10:12 UTC (rev 205359)
@@ -1,5 +1,18 @@
2016-09-02 Chris Dumez <[email protected]>
+ Object.preventExtensions() should throw cross-origin
+ https://bugs.webkit.org/show_bug.cgi?id=161486
+
+ Reviewed by Geoffrey Garen.
+
+ Update JSProxy to forward preventExtensions() calls to its target.
+
+ * runtime/JSProxy.cpp:
+ (JSC::JSProxy::preventExtensions):
+ * runtime/JSProxy.h:
+
+2016-09-02 Chris Dumez <[email protected]>
+
Align proto getter / setter behavior with other browsers
https://bugs.webkit.org/show_bug.cgi?id=161455
Modified: trunk/Source/_javascript_Core/runtime/JSProxy.cpp (205358 => 205359)
--- trunk/Source/_javascript_Core/runtime/JSProxy.cpp 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.cpp 2016-09-02 19:10:12 UTC (rev 205359)
@@ -102,6 +102,12 @@
return thisObject->target()->methodTable(exec->vm())->deleteProperty(thisObject->target(), exec, propertyName);
}
+bool JSProxy::preventExtensions(JSObject* object, ExecState* exec)
+{
+ JSProxy* thisObject = jsCast<JSProxy*>(object);
+ return thisObject->target()->methodTable(exec->vm())->preventExtensions(thisObject->target(), exec);
+}
+
bool JSProxy::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
{
JSProxy* thisObject = jsCast<JSProxy*>(cell);
Modified: trunk/Source/_javascript_Core/runtime/JSProxy.h (205358 => 205359)
--- trunk/Source/_javascript_Core/runtime/JSProxy.h 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/_javascript_Core/runtime/JSProxy.h 2016-09-02 19:10:12 UTC (rev 205359)
@@ -96,6 +96,7 @@
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue, bool shouldThrowIfCantSet);
JS_EXPORT_PRIVATE static JSValue getPrototype(JSObject*, ExecState*);
+ JS_EXPORT_PRIVATE static bool preventExtensions(JSObject*, ExecState*);
private:
WriteBarrier<JSObject> m_target;
Modified: trunk/Source/WebCore/ChangeLog (205358 => 205359)
--- trunk/Source/WebCore/ChangeLog 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/ChangeLog 2016-09-02 19:10:12 UTC (rev 205359)
@@ -1,5 +1,34 @@
2016-09-02 Chris Dumez <[email protected]>
+ Object.preventExtensions() should throw cross-origin
+ https://bugs.webkit.org/show_bug.cgi?id=161486
+
+ Reviewed by Geoffrey Garen.
+
+ Object.preventExtensions() should throw cross-origin:
+ - https://html.spec.whatwg.org/#windowproxy-preventextensions
+ - https://html.spec.whatwg.org/#location-preventextensions
+ - http://www.ecma-international.org/ecma-262/6.0/#sec-object.preventextensions
+
+ Firefox and Chrome both throw in the cross-origin case. Firefox also throws
+ a TypeError in the same-origin case for Window, as per the specification.
+ However, Firefox does not seem to throw yet in the same-origin case for
+ Location yet.
+
+ Test: http/tests/security/preventExtensions-window-location.html
+
+ * bindings/js/JSDOMWindowCustom.cpp:
+ (WebCore::JSDOMWindow::preventExtensions):
+ * bindings/js/JSLocationCustom.cpp:
+ (WebCore::JSLocation::preventExtensions):
+ * bindings/scripts/CodeGeneratorJS.pm:
+ (GenerateHeader):
+ * bindings/scripts/IDLAttributes.txt:
+ * page/DOMWindow.idl:
+ * page/Location.idl:
+
+2016-09-02 Chris Dumez <[email protected]>
+
Object.defineProperty() should throw cross-origin
https://bugs.webkit.org/show_bug.cgi?id=161460
Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp (205358 => 205359)
--- trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp 2016-09-02 19:10:12 UTC (rev 205359)
@@ -361,6 +361,14 @@
return Base::getPrototype(object, exec);
}
+bool JSDOMWindow::preventExtensions(JSObject* object, ExecState* exec)
+{
+ JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object);
+ if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError))
+ return false;
+ return false;
+}
+
// Custom Attributes
void JSDOMWindow::setLocation(ExecState& state, JSValue value)
Modified: trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp (205358 => 205359)
--- trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp 2016-09-02 19:10:12 UTC (rev 205359)
@@ -147,6 +147,16 @@
return Base::getPrototype(object, exec);
}
+bool JSLocation::preventExtensions(JSObject* object, ExecState* exec)
+{
+ JSLocation* thisObject = jsCast<JSLocation*>(object);
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError))
+ return false;
+ // FIXME: The specification says to return false in the same origin case as well but other browsers have
+ // not implemented this yet.
+ return Base::preventExtensions(object, exec);
+}
+
bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult)
{
putResult = false;
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm (205358 => 205359)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm 2016-09-02 19:10:12 UTC (rev 205359)
@@ -1326,6 +1326,9 @@
push (@headerContent, " static JSC::JSValue getPrototype(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{"CustomGetPrototype"};
push (@headerContent, " static bool setPrototype(JSC::JSObject*, JSC::ExecState*, JSC::JSValue, bool shouldThrowIfCantSet);\n") if $interface->extendedAttributes->{"CustomSetPrototype"};
+ # Custom preventExtensions function.
+ push(@headerContent, " static bool preventExtensions(JSC::JSObject*, JSC::ExecState*);\n") if $interface->extendedAttributes->{"CustomPreventExtensions"};
+
# Override toBoolean to return false for objects that want to 'MasqueradesAsUndefined'.
if ($interface->extendedAttributes->{"MasqueradesAsUndefined"}) {
$structureFlags{"JSC::MasqueradesAsUndefined"} = 1;
Modified: trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt (205358 => 205359)
--- trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt 2016-09-02 19:10:12 UTC (rev 205359)
@@ -47,6 +47,7 @@
CustomIsReachable
CustomNamedGetter
CustomNamedSetter
+CustomPreventExtensions
CustomProxyToJSObject
CustomPutFunction
CustomReturn
Modified: trunk/Source/WebCore/page/DOMWindow.idl (205358 => 205359)
--- trunk/Source/WebCore/page/DOMWindow.idl 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/page/DOMWindow.idl 2016-09-02 19:10:12 UTC (rev 205359)
@@ -30,6 +30,7 @@
CustomEnumerateProperty,
CustomGetOwnPropertySlot,
CustomGetPrototype,
+ CustomPreventExtensions,
CustomProxyToJSObject,
CustomPutFunction,
CustomSetPrototype,
Modified: trunk/Source/WebCore/page/Location.idl (205358 => 205359)
--- trunk/Source/WebCore/page/Location.idl 2016-09-02 19:00:22 UTC (rev 205358)
+++ trunk/Source/WebCore/page/Location.idl 2016-09-02 19:10:12 UTC (rev 205359)
@@ -32,6 +32,7 @@
CustomEnumerateProperty,
CustomGetPrototype,
CustomNamedSetter,
+ CustomPreventExtensions,
CustomSetPrototype,
GenerateIsReachable=ImplFrame,
JSCustomDefineOwnProperty,