Bug 1505212 - Test for Partitioned localStorage, r=asuth

This commit is contained in:
Andrea Marchesini 2018-11-13 09:51:14 +01:00
Родитель 375ae1c863
Коммит 23511a2b82
4 изменённых файлов: 616 добавлений и 0 удалений

Просмотреть файл

@ -60,3 +60,6 @@ skip-if = serviceworker_e10s
[browser_storageAccessWithHeuristics.js]
[browser_allowPermissionForTracker.js]
[browser_denyPermissionForTracker.js]
[browser_partitionedLocalStorage.js]
[browser_partitionedLocalStorage_events.js]
support-files = localStorageEvents.html

Просмотреть файл

@ -0,0 +1,46 @@
AntiTracking.runTest("localStorage and Storage Access API",
async _ => {
/* import-globals-from storageAccessAPIHelpers.js */
await noStorageAccessInitially();
localStorage.foo = 42;
ok(true, "LocalStorage is allowed");
is(localStorage.foo, "42", "The value matches");
var prevLocalStorage = localStorage;
/* import-globals-from storageAccessAPIHelpers.js */
await callRequestStorageAccess();
ok(localStorage != prevLocalStorage, "We have a new localStorage");
is(localStorage.foo, undefined, "Undefined value after.");
localStorage.foo = 42;
ok(true, "LocalStorage is still allowed");
is(localStorage.foo, "42", "The value matches");
},
async _ => {
/* import-globals-from storageAccessAPIHelpers.js */
await noStorageAccessInitially();
localStorage.foo = 42;
ok(true, "LocalStorage is allowed");
is(localStorage.foo, "42", "The value matches");
var prevLocalStorage = localStorage;
/* import-globals-from storageAccessAPIHelpers.js */
await callRequestStorageAccess();
// For non-tracking windows, calling the API is a no-op
ok(localStorage == prevLocalStorage, "We have a new localStorage");
is(localStorage.foo, "42", "The value matches");
ok(true, "LocalStorage is allowed");
},
async _ => {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
});
},
[["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"]],
false, false);

Просмотреть файл

@ -0,0 +1,537 @@
// A same origin (and same-process via setting "dom.ipc.processCount" to 1)
// top-level window with access to real localStorage does not share storage
// with an ePartitionOrDeny iframe that should have PartitionedLocalStorage and
// no storage events are received in either direction. (Same-process in order
// to avoid having to worry about any e10s propagation issues.)
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("Creating a tracker top-level context");
let trackerTab = BrowserTestUtils.addTab(gBrowser, TEST_3RD_PARTY_DOMAIN + TEST_PATH + "page.html");
let trackerBrowser = gBrowser.getBrowserForTab(trackerTab);
await BrowserTestUtils.browserLoaded(trackerBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr = content.document.createElement("iframe");
ifr.setAttribute("id", "ifr");
ifr.setAttribute("src", obj.page);
info("Iframe loading...");
await new content.Promise(resolve => {
ifr.onload = resolve;
content.document.body.appendChild(ifr);
});
info("Setting localStorage value...");
ifr.contentWindow.postMessage("setValue", "*");
info("Getting the value...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set by the tracker");
}
);
info("The tracker page should not have received events");
await ContentTask.spawn(trackerBrowser, null, async _ => {
is(content.localStorage.foo, undefined, "Undefined value!");
content.localStorage.foo = "normal-" + Math.random();
}
);
info("Let's see if non-tracker page has received events");
await ContentTask.spawn(normalBrowser, null, async _ => {
let ifr = content.document.getElementById("ifr");
info("Getting the value...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set by the tracker");
info("Getting the events...");
let events = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getEvents", "*");
});
is(events, 0, "No events");
}
);
BrowserTestUtils.removeTab(trackerTab);
BrowserTestUtils.removeTab(normalTab);
});
// Two ePartitionOrDeny iframes in the same tab in the same origin don"t see
// the same localStorage values and no storage events are received from each
// other.
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr1 = content.document.createElement("iframe");
ifr1.setAttribute("id", "ifr1");
ifr1.setAttribute("src", obj.page);
info("Iframe 1 loading...");
await new content.Promise(resolve => {
ifr1.onload = resolve;
content.document.body.appendChild(ifr1);
});
let ifr2 = content.document.createElement("iframe");
ifr2.setAttribute("id", "ifr2");
ifr2.setAttribute("src", obj.page);
info("Iframe 2 loading...");
await new content.Promise(resolve => {
ifr2.onload = resolve;
content.document.body.appendChild(ifr2);
});
info("Setting localStorage value in ifr1...");
ifr1.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr1...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr1.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set in ifr1");
info("Getting the value from ifr2...");
value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr2.contentWindow.postMessage("getValue", "*");
});
is(value, null, "The value is nt set in ifr2");
info("Getting the events received by ifr2...");
let events = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr2.contentWindow.postMessage("getEvents", "*");
});
is(events, 0, "No events");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// Same as the previous test but with a cookie behavior of BEHAVIOR_ACCEPT
// instead of BEHAVIOR_REJECT_TRACKER so the iframes get real, persistent
// localStorage instead of partitioned localStorage.
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_ACCEPT],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr1 = content.document.createElement("iframe");
ifr1.setAttribute("id", "ifr1");
ifr1.setAttribute("src", obj.page);
info("Iframe 1 loading...");
await new content.Promise(resolve => {
ifr1.onload = resolve;
content.document.body.appendChild(ifr1);
});
let ifr2 = content.document.createElement("iframe");
ifr2.setAttribute("id", "ifr2");
ifr2.setAttribute("src", obj.page);
info("Iframe 2 loading...");
await new content.Promise(resolve => {
ifr2.onload = resolve;
content.document.body.appendChild(ifr2);
});
info("Setting localStorage value in ifr1...");
ifr1.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr1...");
let value1 = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr1.contentWindow.postMessage("getValue", "*");
});
ok(value1.startsWith("tracker-"), "The value is correctly set in ifr1");
info("Getting the value from ifr2...");
let value2 = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr2.contentWindow.postMessage("getValue", "*");
});
is(value2, value1, "The values match");
info("Getting the events received by ifr2...");
let events = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr2.contentWindow.postMessage("getEvents", "*");
});
is(events, 1, "One event");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// An ePartitionOrDeny iframe navigated between two distinct pages on the same
// origin does not see the values stored by the previous iframe.
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr = content.document.createElement("iframe");
ifr.setAttribute("id", "ifr");
ifr.setAttribute("src", obj.page);
info("Iframe loading...");
await new content.Promise(resolve => {
ifr.onload = resolve;
content.document.body.appendChild(ifr);
});
info("Setting localStorage value in ifr...");
ifr.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set in ifr");
info("Navigate...");
await new content.Promise(resolve => {
ifr.onload = resolve;
ifr.setAttribute("src", obj.page + "?" + Math.random());
});
info("Getting the value from ifr...");
value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
is(value, null, "The value is undefined");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// Like the previous test, but accepting trackers
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_ACCEPT],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr = content.document.createElement("iframe");
ifr.setAttribute("id", "ifr");
ifr.setAttribute("src", obj.page);
info("Iframe loading...");
await new content.Promise(resolve => {
ifr.onload = resolve;
content.document.body.appendChild(ifr);
});
info("Setting localStorage value in ifr...");
ifr.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set in ifr");
info("Navigate...");
await new content.Promise(resolve => {
ifr.onload = resolve;
ifr.setAttribute("src", obj.page + "?" + Math.random());
});
info("Getting the value from ifr...");
let value2 = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
is(value, value2, "The value is undefined");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// An ePartitionOrDeny iframe on the same origin that is navigated to itself
// via window.location.reload() or equivalent does not see the values stored by
// its previous self.
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr = content.document.createElement("iframe");
ifr.setAttribute("id", "ifr");
ifr.setAttribute("src", obj.page);
info("Iframe loading...");
await new content.Promise(resolve => {
ifr.onload = resolve;
content.document.body.appendChild(ifr);
});
info("Setting localStorage value in ifr...");
ifr.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set in ifr");
info("Reload...");
await new content.Promise(resolve => {
ifr.onload = resolve;
ifr.contentWindow.postMessage("reload", "*");
});
info("Getting the value from ifr...");
value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
is(value, null, "The value is undefined");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// Like the previous test, but accepting trackers
add_task(async _ => {
await SpecialPowers.pushPrefEnv({"set": [
["dom.ipc.processCount", 1],
["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_ACCEPT],
["privacy.trackingprotection.enabled", false],
["privacy.trackingprotection.pbmode.enabled", false],
["privacy.trackingprotection.annotate_channels", true],
["browser.fastblock.enabled", false], // prevent intermittent failures
["privacy.restrict3rdpartystorage.partitionedHosts", "tracking.example.org,tracking.example.com"],
]});
await UrlClassifierTestUtils.addTestTrackers();
info("Creating a non-tracker top-level context");
let normalTab = BrowserTestUtils.addTab(gBrowser, TEST_DOMAIN + TEST_PATH + "page.html");
let normalBrowser = gBrowser.getBrowserForTab(normalTab);
await BrowserTestUtils.browserLoaded(normalBrowser);
info("The non-tracker page opens a tracker iframe");
await ContentTask.spawn(normalBrowser, {
page: TEST_3RD_PARTY_DOMAIN + TEST_PATH + "localStorageEvents.html",
}, async obj => {
let ifr = content.document.createElement("iframe");
ifr.setAttribute("id", "ifr");
ifr.setAttribute("src", obj.page);
info("Iframe loading...");
await new content.Promise(resolve => {
ifr.onload = resolve;
content.document.body.appendChild(ifr);
});
info("Setting localStorage value in ifr...");
ifr.contentWindow.postMessage("setValue", "*");
info("Getting the value from ifr...");
let value = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
ok(value.startsWith("tracker-"), "The value is correctly set in ifr");
info("Reload...");
await new content.Promise(resolve => {
ifr.onload = resolve;
ifr.contentWindow.postMessage("reload", "*");
});
info("Getting the value from ifr...");
let value2 = await new Promise(resolve => {
content.addEventListener("message", e => {
resolve(e.data);
}, {once: true});
ifr.contentWindow.postMessage("getValue", "*");
});
is(value, value2, "The value is undefined");
}
);
BrowserTestUtils.removeTab(normalTab);
});
// Cleanup data.
add_task(async _ => {
await new Promise(resolve => {
Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve());
});
});

Просмотреть файл

@ -0,0 +1,30 @@
<script>
let eventCounter = 0;
onmessage = e => {
if (e.data == "getValue") {
parent.postMessage(localStorage.foo, "*");
return;
}
if (e.data == "setValue") {
localStorage.foo = "tracker-" + Math.random();
return;
}
if (e.data == "getEvents") {
parent.postMessage(eventCounter, "*");
return;
}
if (e.data == "reload") {
window.location.reload();
}
};
addEventListener("storage", _ => {
++eventCounter;
});
</script>