Setting Window.opener to null should disown its opener
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Jan 2018 04:47:31 +0000 (04:47 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 12 Jan 2018 04:47:31 +0000 (04:47 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181505
<rdar://problem/36443151>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Setting Window.opener to null should disown its opener as per:
- https://html.spec.whatwg.org/#dom-opener

With this change, tabs opened by clicking link inside Gmail no
longer have the Gmail window as opener.

Tests: fast/dom/Window/window-opener-set-to-null.html
       fast/dom/Window/window-opener-shadowing.html

* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::setOpener):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::disownOpener):
* page/DOMWindow.h:
* page/DOMWindow.idl:

LayoutTests:

Add layout test coverage.

* fast/dom/Window/window-opener-set-to-null-expected.txt: Added.
* fast/dom/Window/window-opener-set-to-null.html: Added.
* fast/dom/Window/window-opener-shadowing-expected.txt: Added.
* fast/dom/Window/window-opener-shadowing.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@226842 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/dom/Window/window-opener-set-to-null-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/Window/window-opener-set-to-null.html [new file with mode: 0644]
LayoutTests/fast/dom/Window/window-opener-shadowing-expected.txt [new file with mode: 0644]
LayoutTests/fast/dom/Window/window-opener-shadowing.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/DOMWindow.h
Source/WebCore/page/DOMWindow.idl

index f886e80..19041a7 100644 (file)
@@ -1,3 +1,18 @@
+2018-01-11  Chris Dumez  <cdumez@apple.com>
+
+        Setting Window.opener to null should disown its opener
+        https://bugs.webkit.org/show_bug.cgi?id=181505
+        <rdar://problem/36443151>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add layout test coverage.
+
+        * fast/dom/Window/window-opener-set-to-null-expected.txt: Added.
+        * fast/dom/Window/window-opener-set-to-null.html: Added.
+        * fast/dom/Window/window-opener-shadowing-expected.txt: Added.
+        * fast/dom/Window/window-opener-shadowing.html: Added.
+
 2018-01-11  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [Cocoa] Star character disappears when bolded
diff --git a/LayoutTests/fast/dom/Window/window-opener-set-to-null-expected.txt b/LayoutTests/fast/dom/Window/window-opener-set-to-null-expected.txt
new file mode 100644 (file)
index 0000000..e41df46
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that setting window.opener to null disown its opener
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS newWindow.opener is window
+PASS newWindow.opener = null did not throw exception.
+PASS newWindow.opener is null
+PASS openerGetter.call(newWindow) is null
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/Window/window-opener-set-to-null.html b/LayoutTests/fast/dom/Window/window-opener-set-to-null.html
new file mode 100644 (file)
index 0000000..37ec9e1
--- /dev/null
@@ -0,0 +1,28 @@
+<DOCTYPE html>
+<html>
+<body>
+<script src="../../../resources/js-test.js"></script>
+<script>
+description("Tests that setting window.opener to null disown its opener");
+jsTestIsAsync = true;
+
+onload = function() {
+  if (window.testRunner)
+    testRunner.setCanOpenWindows();
+
+  newWindow = open("resources/blank.html");
+  newWindow.onload = function() {
+    shouldBe("newWindow.opener", "window");
+
+    openerGetter = Object.getOwnPropertyDescriptor(newWindow, "opener").get;
+
+    shouldNotThrow("newWindow.opener = null");
+    shouldBeNull("newWindow.opener");
+    shouldBeNull("openerGetter.call(newWindow)");
+
+    finishJSTest();
+  };
+};
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/dom/Window/window-opener-shadowing-expected.txt b/LayoutTests/fast/dom/Window/window-opener-shadowing-expected.txt
new file mode 100644 (file)
index 0000000..4b20e41
--- /dev/null
@@ -0,0 +1,27 @@
+Tests shadowing of window.opener property
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS window.opener is null
+desc = Object.getOwnPropertyDescriptor(window, 'opener')
+PASS desc.get is an instance of Function
+PASS desc.set is an instance of Function
+PASS desc.enumerable is true
+PASS desc.configurable is true
+PASS window.opener = 'foo' did not throw exception.
+desc = Object.getOwnPropertyDescriptor(window, 'opener')
+PASS desc.value is "foo"
+PASS desc.writable is true
+PASS desc.enumerable is true
+PASS desc.configurable is true
+PASS openerGetter.call(window) is null
+PASS delete window.opener did not throw exception.
+PASS window.opener is undefined.
+PASS openerGetter.call(window) is null
+desc = Object.getOwnPropertyDescriptor(window, 'opener')
+PASS desc is undefined.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/dom/Window/window-opener-shadowing.html b/LayoutTests/fast/dom/Window/window-opener-shadowing.html
new file mode 100644 (file)
index 0000000..3bd47ed
--- /dev/null
@@ -0,0 +1,36 @@
+<DOCTYPE html>
+<html>
+<body>
+<script src="../../../resources/js-test.js"></script>
+<script>
+description("Tests shadowing of window.opener property");
+
+shouldBeNull("window.opener");
+evalAndLog("desc = Object.getOwnPropertyDescriptor(window, 'opener')");
+shouldBeType("desc.get", "Function");
+shouldBeType("desc.set", "Function");
+shouldBeTrue("desc.enumerable");
+shouldBeTrue("desc.configurable");
+
+openerGetter = desc.get;
+
+shouldNotThrow("window.opener = 'foo'");
+evalAndLog("desc = Object.getOwnPropertyDescriptor(window, 'opener')");
+
+shouldBeEqualToString("desc.value", "foo");
+shouldBeTrue("desc.writable");
+shouldBeTrue("desc.enumerable");
+shouldBeTrue("desc.configurable");
+
+shouldBeNull("openerGetter.call(window)");
+
+shouldNotThrow("delete window.opener");
+shouldBeUndefined("window.opener");
+
+shouldBeNull("openerGetter.call(window)");
+
+evalAndLog("desc = Object.getOwnPropertyDescriptor(window, 'opener')");
+shouldBeUndefined("desc");
+</script>
+</body>
+</html>
index 801e722..2ecd2d5 100644 (file)
@@ -1,3 +1,27 @@
+2018-01-11  Chris Dumez  <cdumez@apple.com>
+
+        Setting Window.opener to null should disown its opener
+        https://bugs.webkit.org/show_bug.cgi?id=181505
+        <rdar://problem/36443151>
+
+        Reviewed by Ryosuke Niwa.
+
+        Setting Window.opener to null should disown its opener as per:
+        - https://html.spec.whatwg.org/#dom-opener
+
+        With this change, tabs opened by clicking link inside Gmail no
+        longer have the Gmail window as opener.
+
+        Tests: fast/dom/Window/window-opener-set-to-null.html
+               fast/dom/Window/window-opener-shadowing.html
+
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::setOpener):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::disownOpener):
+        * page/DOMWindow.h:
+        * page/DOMWindow.idl:
+
 2018-01-11  Myles C. Maxfield  <mmaxfield@apple.com>
 
         [Cocoa] Star character disappears when bolded
index 9a92d16..ba9d2b7 100644 (file)
@@ -466,4 +466,16 @@ DOMWindow* JSDOMWindow::toWrapped(VM& vm, JSValue value)
     return nullptr;
 }
 
+void JSDOMWindow::setOpener(JSC::ExecState& state, JSC::JSValue value)
+{
+    if (!BindingSecurity::shouldAllowAccessToDOMWindow(&state, wrapped(), ThrowSecurityError))
+        return;
+
+    if (value.isNull()) {
+        wrapped().disownOpener();
+        return;
+    }
+    replaceStaticPropertySlot(state.vm(), this, Identifier::fromString(&state.vm(), "opener"), value);
+}
+
 } // namespace WebCore
index 5b4b711..f1d1985 100644 (file)
@@ -1425,6 +1425,12 @@ DOMWindow* DOMWindow::opener() const
     return opener->document()->domWindow();
 }
 
+void DOMWindow::disownOpener()
+{
+    if (m_frame)
+        m_frame->loader().setOpener(nullptr);
+}
+
 DOMWindow* DOMWindow::parent() const
 {
     if (!m_frame)
index 7f477b2..7748efa 100644 (file)
@@ -198,6 +198,7 @@ public:
     DOMWindow* frames() const { return self(); }
 
     DOMWindow* opener() const;
+    void disownOpener();
     DOMWindow* parent() const;
     DOMWindow* top() const;
 
index 02ebbba..801a0fb 100644 (file)
@@ -73,7 +73,7 @@ typedef USVString CSSOMString;
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow frames;
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute unsigned long length;
     [DoNotCheckSecurityOnGetter, Unforgeable] readonly attribute DOMWindow? top;
-    [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow? opener;
+    [DoNotCheckSecurityOnGetter, CustomSetter] attribute DOMWindow? opener;
     [Replaceable, DoNotCheckSecurityOnGetter] readonly attribute DOMWindow? parent;
     [CheckSecurityForNode] readonly attribute Element? frameElement;
     [CallWith=ActiveWindow&FirstWindow] DOMWindow? open(optional USVString url = "about:blank", optional DOMString target = "_blank", optional [TreatNullAs=EmptyString] DOMString features = "");