Bug 2027823 - Pay attention to storage partitioning for sessionStorage cloning in window.open - r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D290965
This commit is contained in:
committed by
bvandersloot@mozilla.com
parent
a0f07ee021
commit
3de9960e92
@@ -22,15 +22,6 @@ add_task(async function () {
|
||||
`cross-origin site and then navigating back`
|
||||
);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
[
|
||||
"privacy.partition.always_partition_third_party_non_cookie_storage",
|
||||
false,
|
||||
],
|
||||
],
|
||||
});
|
||||
|
||||
BrowserTestUtils.startLoadingURIString(browser, URL1);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
@@ -104,8 +95,8 @@ add_task(async function () {
|
||||
|
||||
await SpecialPowers.spawn(
|
||||
browser,
|
||||
[ORIGIN2, ORIGIN1, URL1, key, value],
|
||||
async (ORIGIN, iframeORIGIN, iframeURL, key, value) => {
|
||||
[ORIGIN2, ORIGIN1, URL1, key],
|
||||
async (ORIGIN, iframeORIGIN, iframeURL, key) => {
|
||||
is(content.window.origin, ORIGIN, `Navigate to ${ORIGIN} as expected`);
|
||||
|
||||
let iframe = content.document.createElement("iframe");
|
||||
@@ -115,32 +106,20 @@ add_task(async function () {
|
||||
|
||||
await content.SpecialPowers.spawn(
|
||||
iframe,
|
||||
[iframeORIGIN, key, value],
|
||||
async function (ORIGIN, key, value) {
|
||||
[iframeORIGIN, key],
|
||||
async function (ORIGIN, key) {
|
||||
is(
|
||||
content.window.origin,
|
||||
ORIGIN,
|
||||
`Navigate to ${ORIGIN} as expected`
|
||||
);
|
||||
|
||||
// Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
|
||||
// Acquire storage access permission here so that the iframe has
|
||||
// first-party access to the sessionStorage. Without this, it is
|
||||
// isolated and this test will always fail
|
||||
SpecialPowers.wrap(content.document).notifyUserGestureActivation();
|
||||
await SpecialPowers.addPermission(
|
||||
"storageAccessAPI",
|
||||
true,
|
||||
content.window.location.href
|
||||
);
|
||||
await SpecialPowers.wrap(content.document).requestStorageAccess();
|
||||
|
||||
let value1 = content.window.sessionStorage.getItem(key);
|
||||
is(
|
||||
value1,
|
||||
value,
|
||||
null,
|
||||
`SessionStorage for ${key} in ${content.window.origin} is ` +
|
||||
`preserved`
|
||||
`partitioned and should not see the top-level value`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
const bc = SpecialPowers.wrap(BroadcastChannel)
|
||||
.unpartitionedTestingChannel("sessionStorageTargetBlank");
|
||||
bc.postMessage({
|
||||
key1: sessionStorage.getItem("key1"),
|
||||
length: sessionStorage.length,
|
||||
hasOpener: !!window.opener,
|
||||
});
|
||||
bc.close();
|
||||
parent.close();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
This page is opened as a popup in xorigin mode by test_sessionStorageTargetBlank.html.
|
||||
It embeds file_targetBlankChild.html in an iframe from the test origin so it
|
||||
runs in the same storage partition as the test.
|
||||
-->
|
||||
<body>
|
||||
<script>
|
||||
let params = new URLSearchParams(location.search);
|
||||
let origin = params.get("origin");
|
||||
let iframe = document.createElement("iframe");
|
||||
let path = location.pathname.replace(
|
||||
"file_targetBlankChild_xorigin_wrapper.html",
|
||||
"file_targetBlankChild.html");
|
||||
iframe.src = origin + path;
|
||||
document.body.appendChild(iframe);
|
||||
</script>
|
||||
</html>
|
||||
@@ -2,6 +2,8 @@
|
||||
support-files = [
|
||||
"file_http.html",
|
||||
"file_https.html",
|
||||
"file_targetBlankChild.html",
|
||||
"file_targetBlankChild_xorigin_wrapper.html",
|
||||
"frameEqual.html",
|
||||
"frameNotEqual.html",
|
||||
"frameReplace.html",
|
||||
@@ -31,4 +33,10 @@ skip-if = [
|
||||
"http3",
|
||||
]
|
||||
|
||||
["test_sessionStorageTargetBlank.html"]
|
||||
skip-if = [
|
||||
"http2",
|
||||
"http3",
|
||||
]
|
||||
|
||||
["test_sessionStorageUsage.html"]
|
||||
|
||||
@@ -16,8 +16,6 @@ async function doNextTest()
|
||||
// Make sure we do not unpartition storage inappropriately
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["privacy.partition.always_partition_third_party_non_cookie_storage", true],
|
||||
["privacy.partition.always_partition_third_party_non_cookie_storage.exempt_sessionstorage", false],
|
||||
["privacy.restrict3rdpartystorage.heuristic.window_open", false],
|
||||
],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>sessionStorage cloning with target=_blank and noopener</title>
|
||||
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
async function runTest() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["test.events.async.enabled", false],
|
||||
],
|
||||
});
|
||||
|
||||
if (isXOrigin) {
|
||||
let path = location.pathname.replace(
|
||||
"test_sessionStorageTargetBlank.html",
|
||||
"file_targetBlankChild_xorigin_wrapper.html");
|
||||
let wrapperUrl = "http://mochi.xorigin-test:8888" + path +
|
||||
"?origin=" + encodeURIComponent(location.origin);
|
||||
document.getElementById("link-opener").href = wrapperUrl;
|
||||
document.getElementById("link-noopener").href = wrapperUrl;
|
||||
}
|
||||
|
||||
sessionStorage.clear();
|
||||
sessionStorage.setItem("key1", "value1");
|
||||
|
||||
// Test 1: target="_blank" (implicit noopener) — sessionStorage should NOT
|
||||
// be cloned because target=_blank implies noopener per the HTML spec.
|
||||
let bc = SpecialPowers.wrap(BroadcastChannel)
|
||||
.unpartitionedTestingChannel("sessionStorageTargetBlank");
|
||||
let resultPromise = new Promise(resolve => {
|
||||
bc.onmessage = e => {
|
||||
resolve(e.data);
|
||||
}
|
||||
});
|
||||
synthesizeMouseAtCenter(document.getElementById("link-opener"), {});
|
||||
let result = await resultPromise;
|
||||
bc.close();
|
||||
|
||||
is(result.hasOpener, false, "target=_blank: should not have opener (implicit noopener)");
|
||||
is(result.key1, null, "target=_blank: key1 should not be present");
|
||||
is(result.length, 0, "target=_blank: should have 0 items");
|
||||
|
||||
// Test 2: rel="noopener" target="_blank" — sessionStorage should NOT be cloned
|
||||
bc = SpecialPowers.wrap(BroadcastChannel)
|
||||
.unpartitionedTestingChannel("sessionStorageTargetBlank");
|
||||
resultPromise = new Promise(resolve => {
|
||||
bc.onmessage = e => {
|
||||
resolve(e.data);
|
||||
}
|
||||
});
|
||||
synthesizeMouseAtCenter(document.getElementById("link-noopener"), {});
|
||||
result = await resultPromise;
|
||||
bc.close();
|
||||
|
||||
is(result.hasOpener, false, "noopener target=_blank: should not have opener");
|
||||
is(result.key1, null, "noopener target=_blank: key1 should not be present");
|
||||
is(result.length, 0, "noopener target=_blank: should have 0 items");
|
||||
|
||||
sessionStorage.clear();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();">
|
||||
<a id="link-opener" href="file_targetBlankChild.html" target="_blank">Open with opener</a>
|
||||
<br/>
|
||||
<a id="link-noopener" href="file_targetBlankChild.html" rel="noopener" target="_blank">Open without opener</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1318,9 +1318,15 @@ nsresult nsWindowWatcher::OpenWindowInternal(
|
||||
targetDocShell->GetBrowsingContext()->GetSessionStorageManager();
|
||||
|
||||
if (parentStorageManager && newStorageManager) {
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal;
|
||||
if (parentDoc) {
|
||||
storagePrincipal = parentDoc->EffectiveStoragePrincipal();
|
||||
} else {
|
||||
storagePrincipal = subjectPrincipal;
|
||||
}
|
||||
RefPtr<Storage> storage;
|
||||
parentStorageManager->GetStorage(
|
||||
parentInnerWin, subjectPrincipal, subjectPrincipal,
|
||||
parentInnerWin, subjectPrincipal, storagePrincipal,
|
||||
targetBC->UsePrivateBrowsing(), getter_AddRefs(storage));
|
||||
if (storage) {
|
||||
newStorageManager->CloneStorage(storage);
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
<!--
|
||||
This page is opened in a new window by test_storage_copied.html.
|
||||
We need to return the sessionStorage value for the item "test-item",
|
||||
by way of postMessage.
|
||||
by way of postMessage to the opener.
|
||||
-->
|
||||
<head>
|
||||
<body>Opened!</body>
|
||||
<script>
|
||||
window.postMessage(window.sessionStorage.getItem("test-item"), "*");
|
||||
let target = window.opener || window.parent;
|
||||
target.postMessage(
|
||||
window.sessionStorage.getItem("test-item"), "*");
|
||||
</script>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
This page is opened as a popup in xorigin mode by test_storage_copied.html.
|
||||
It embeds file_storage_copied.html in an iframe from the test origin so it
|
||||
runs in the same storage partition as the test, then relays the result to
|
||||
the opener.
|
||||
-->
|
||||
<body>Wrapper!</body>
|
||||
<script>
|
||||
let params = new URLSearchParams(location.search);
|
||||
let origin = params.get("origin");
|
||||
let iframe = document.createElement("iframe");
|
||||
let path = location.pathname.replace(
|
||||
"file_storage_copied_xorigin_wrapper.html", "file_storage_copied.html");
|
||||
iframe.src = origin + path;
|
||||
window.addEventListener("message", function(event) {
|
||||
if (window.opener) {
|
||||
window.opener.postMessage(event.data, "*");
|
||||
}
|
||||
});
|
||||
document.body.appendChild(iframe);
|
||||
</script>
|
||||
</html>
|
||||
@@ -10,4 +10,7 @@ skip-if = [
|
||||
support-files = ["file_named_window.html"]
|
||||
|
||||
["test_storage_copied.html"]
|
||||
support-files = ["file_storage_copied.html"]
|
||||
support-files = [
|
||||
"file_storage_copied.html",
|
||||
"file_storage_copied_xorigin_wrapper.html",
|
||||
]
|
||||
|
||||
@@ -15,9 +15,9 @@ same domain as the opener.
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
function waitForMessage(win) {
|
||||
function waitForMessage() {
|
||||
return new Promise(resolve => {
|
||||
win.addEventListener("message", function(event) {
|
||||
window.addEventListener("message", function(event) {
|
||||
resolve(event.data);
|
||||
}, {once: true});
|
||||
});
|
||||
@@ -33,8 +33,24 @@ same domain as the opener.
|
||||
]});
|
||||
|
||||
window.sessionStorage.setItem("test-item", TEST_VALUE);
|
||||
let win = window.open("file_storage_copied.html", "my_window");
|
||||
let data = await waitForMessage(win);
|
||||
|
||||
let popupUrl;
|
||||
if (isXOrigin) {
|
||||
// In xorigin mode, this test runs in a third-party iframe
|
||||
// (mochi.test inside mochi.xorigin-test). Open the popup on the
|
||||
// top-level origin so it can embed a frame with the same partition
|
||||
// key, allowing the cloned sessionStorage to be read.
|
||||
let path = location.pathname.replace(
|
||||
"test_storage_copied.html", "file_storage_copied_xorigin_wrapper.html");
|
||||
popupUrl = "http://mochi.xorigin-test:8888" + path +
|
||||
"?origin=" + encodeURIComponent(location.origin);
|
||||
} else {
|
||||
popupUrl = "file_storage_copied.html";
|
||||
}
|
||||
|
||||
let loadPromise = waitForMessage();
|
||||
let win = window.open(popupUrl, "my_window");
|
||||
let data = await loadPromise;
|
||||
is(data, TEST_VALUE, "Should have cloned the test value");
|
||||
win.close();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user