545 lines
14 KiB
JavaScript
545 lines
14 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
|
|
"use strict";
|
|
|
|
const TEST_CROSS_SITE_DOMAIN = "https://example.net/";
|
|
const TEST_CROSS_SITE_PAGE =
|
|
TEST_CROSS_SITE_DOMAIN + TEST_PATH + "file_empty.html";
|
|
|
|
add_setup(async function () {
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
["dom.serviceWorkers.enabled", true],
|
|
["dom.serviceWorkers.testing.enabled", true],
|
|
],
|
|
});
|
|
|
|
Services.cookies.removeAll();
|
|
});
|
|
|
|
function registerSW(browser) {
|
|
return SpecialPowers.spawn(browser, [], async _ => {
|
|
let reg =
|
|
await content.navigator.serviceWorker.register("serviceWorker.js");
|
|
|
|
await ContentTaskUtils.waitForCondition(() => {
|
|
return reg.active && reg.active.state === "activated";
|
|
}, "The service worker is activated");
|
|
|
|
ok(
|
|
content.navigator.serviceWorker.controller,
|
|
"The service worker controls the document successfully."
|
|
);
|
|
});
|
|
}
|
|
|
|
function fetchCookiesFromSW(browser) {
|
|
return SpecialPowers.spawn(browser, [], async _ => {
|
|
return new content.Promise(resolve => {
|
|
content.navigator.serviceWorker.addEventListener("message", event => {
|
|
resolve(event.data.content);
|
|
});
|
|
|
|
content.navigator.serviceWorker.controller.postMessage({
|
|
action: "fetch",
|
|
url: `cookies.sjs`,
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function setCookiesFromSW(browser, cookies) {
|
|
let setCookieQuery = "";
|
|
|
|
for (let cookie of cookies) {
|
|
setCookieQuery += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
return SpecialPowers.spawn(browser, [setCookieQuery], async query => {
|
|
return new content.Promise(resolve => {
|
|
content.navigator.serviceWorker.addEventListener("message", event => {
|
|
resolve(event.data.content);
|
|
});
|
|
|
|
content.navigator.serviceWorker.controller.postMessage({
|
|
action: "fetch",
|
|
url: `cookies.sjs?${query}`,
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function unregisterSW(browser) {
|
|
return SpecialPowers.spawn(browser, [], async _ => {
|
|
const regs = await content.navigator.serviceWorker.getRegistrations();
|
|
for (const reg of regs) {
|
|
await reg.unregister();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Verify a first-party service worker can access both SameSite=None and
|
|
* SameSite=Lax cookies set in the first-party context.
|
|
*/
|
|
add_task(async function testCookiesWithFirstPartyServiceWorker() {
|
|
info("Open a tab");
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_TOP_PAGE
|
|
);
|
|
|
|
info("Writing cookies to the first-party context.");
|
|
await SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
|
|
const cookies = [
|
|
"foo=bar; SameSite=None; Secure",
|
|
"fooLax=barLax; SameSite=Lax; Secure",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info("Register a service worker and trigger a fetch request to get cookies.");
|
|
await registerSW(tab.linkedBrowser);
|
|
let cookieStr = await fetchCookiesFromSW(tab.linkedBrowser);
|
|
|
|
is(cookieStr, "foo=bar; fooLax=barLax", "The cookies are expected");
|
|
|
|
info("Set cookies from the service worker.");
|
|
await setCookiesFromSW(tab.linkedBrowser, [
|
|
"foo=barSW; SameSite=None; Secure",
|
|
"fooLax=barLaxSW; SameSite=Lax; Secure",
|
|
]);
|
|
|
|
info("Get cookies from the service worker.");
|
|
cookieStr = await fetchCookiesFromSW(tab.linkedBrowser);
|
|
|
|
is(cookieStr, "foo=barSW; fooLax=barLaxSW", "The cookies are expected");
|
|
|
|
await unregisterSW(tab.linkedBrowser);
|
|
BrowserTestUtils.removeTab(tab);
|
|
Services.cookies.removeAll();
|
|
});
|
|
|
|
/**
|
|
* Verify a cross-site service worker can only access cookies set in the
|
|
* same cross-site context.
|
|
*/
|
|
add_task(async function testCookiesWithCrossSiteServiceWorker() {
|
|
// Disable blocking third-party cookies.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["network.cookie.cookieBehavior.optInPartitioning", false]],
|
|
});
|
|
|
|
info("Open a cross-site tab");
|
|
let crossSiteTab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_CROSS_SITE_PAGE
|
|
);
|
|
|
|
info("Writing cookies to the cross site in the first-party context.");
|
|
await SpecialPowers.spawn(crossSiteTab.linkedBrowser, [], async _ => {
|
|
const cookies = [
|
|
"foo=bar; SameSite=None; Secure",
|
|
"fooLax=barLax; SameSite=Lax; Secure",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info("Open a tab");
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_TOP_PAGE
|
|
);
|
|
|
|
info("Load a cross-site iframe");
|
|
let crossSiteBc = await SpecialPowers.spawn(
|
|
tab.linkedBrowser,
|
|
[TEST_CROSS_SITE_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
info("Write cookies in the cross-site iframe");
|
|
await SpecialPowers.spawn(crossSiteBc, [], async _ => {
|
|
const cookies = [
|
|
"foo=crossBar; SameSite=None; Secure",
|
|
"fooLax=crossBarLax; SameSite=Lax; Secure",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info(
|
|
"Register a service worker and trigger a fetch request to get cookies in cross-site context."
|
|
);
|
|
await registerSW(crossSiteBc);
|
|
let cookieStr = await fetchCookiesFromSW(crossSiteBc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"foo=crossBar",
|
|
"Only the SameSite=None cookie set in the third-party iframe is available."
|
|
);
|
|
|
|
info("Set cookies from the third-party service worker.");
|
|
await setCookiesFromSW(crossSiteBc, [
|
|
"foo=crossBarSW; SameSite=None; Secure",
|
|
"fooLax=crossBarLaxSW; SameSite=Lax; Secure",
|
|
]);
|
|
|
|
info("Get cookies from the third-party service worker.");
|
|
cookieStr = await fetchCookiesFromSW(crossSiteBc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"foo=crossBarSW",
|
|
"Only the SameSite=None cookie set in the third-party service worker is available."
|
|
);
|
|
|
|
await unregisterSW(crossSiteBc);
|
|
BrowserTestUtils.removeTab(crossSiteTab);
|
|
BrowserTestUtils.removeTab(tab);
|
|
Services.cookies.removeAll();
|
|
});
|
|
|
|
/**
|
|
* Verify a cross-site service worker can only access partitioned cookies set in
|
|
* the same cross-site context if third-party cookies are blocked.
|
|
*/
|
|
add_task(async function testPartitionedCookiesWithCrossSiteServiceWorker() {
|
|
// Enable blocking third-party cookies.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
["network.cookie.cookieBehavior.optInPartitioning", true],
|
|
["network.cookie.CHIPS.enabled", true],
|
|
],
|
|
});
|
|
|
|
info("Open a tab");
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_TOP_PAGE
|
|
);
|
|
|
|
info("Load a cross-site iframe");
|
|
let crossSiteBc = await SpecialPowers.spawn(
|
|
tab.linkedBrowser,
|
|
[TEST_CROSS_SITE_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
info("Write cookies in the cross-site iframe");
|
|
await SpecialPowers.spawn(crossSiteBc, [], async _ => {
|
|
const cookies = [
|
|
"foo=crossBar; SameSite=None; Secure",
|
|
"fooLax=crossBarLax; SameSite=Lax; Secure",
|
|
"fooPartitioned=crossBar; SameSite=None; Secure; Partitioned;",
|
|
"fooLaxPartitioned=crossBarLax; SameSite=Lax; Secure; Partitioned;",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info(
|
|
"Register a service worker and trigger a fetch request to get cookies in cross-site context."
|
|
);
|
|
await registerSW(crossSiteBc);
|
|
let cookieStr = await fetchCookiesFromSW(crossSiteBc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooPartitioned=crossBar",
|
|
"Only the SameSite=None partitioned cookie set in the third-party iframe is available."
|
|
);
|
|
|
|
info("Set cookies from the third-party service worker.");
|
|
await setCookiesFromSW(crossSiteBc, [
|
|
"foo=crossBarSW; SameSite=None; Secure",
|
|
"fooLax=crossBarLaxSW; SameSite=Lax; Secure",
|
|
"fooPartitioned=crossBarSW; SameSite=None; Secure; Partitioned;",
|
|
"fooLaxPartitioned=crossBarLaxSW; SameSite=Lax; Secure; Partitioned;",
|
|
]);
|
|
|
|
info("Get cookies from the third-party service worker.");
|
|
cookieStr = await fetchCookiesFromSW(crossSiteBc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooPartitioned=crossBarSW",
|
|
"Only the SameSite=None partitioned cookie set in the third-party service worker is available."
|
|
);
|
|
|
|
await unregisterSW(crossSiteBc);
|
|
BrowserTestUtils.removeTab(tab);
|
|
Services.cookies.removeAll();
|
|
});
|
|
|
|
/**
|
|
* Verify a ABA service worker can only access cookies set in the ABA context.
|
|
*/
|
|
add_task(async function testCookiesWithABAServiceWorker() {
|
|
// Disable blocking third-party cookies.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [["network.cookie.cookieBehavior.optInPartitioning", false]],
|
|
});
|
|
|
|
info("Open a tab");
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_TOP_PAGE
|
|
);
|
|
|
|
info("Writing cookies to the first-party context.");
|
|
await SpecialPowers.spawn(tab.linkedBrowser, [], async _ => {
|
|
const cookies = [
|
|
"foo=bar; SameSite=None; Secure",
|
|
"fooLax=barLax; SameSite=Lax; Secure",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info("Load a ABA iframe");
|
|
let crossSiteBc = await SpecialPowers.spawn(
|
|
tab.linkedBrowser,
|
|
[TEST_CROSS_SITE_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
let ABABc = await SpecialPowers.spawn(
|
|
crossSiteBc,
|
|
[TEST_TOP_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
info(
|
|
"Register a service worker and trigger a fetch request to get cookies in the ABA context."
|
|
);
|
|
|
|
await registerSW(ABABc);
|
|
let cookieStr = await fetchCookiesFromSW(ABABc);
|
|
is(cookieStr, "", "No cookie should be available in ABA context.");
|
|
|
|
info("Set cookies in the ABA iframe");
|
|
await SpecialPowers.spawn(ABABc, [], async _ => {
|
|
const cookies = [
|
|
"fooABA=barABA; SameSite=None; Secure",
|
|
"fooABALax=BarABALax; SameSite=Lax; Secure",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info("Get cookies in the ABA service worker.");
|
|
cookieStr = await fetchCookiesFromSW(ABABc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooABA=barABA",
|
|
"Only the SameSite=None cookie set in ABA iframe is available."
|
|
);
|
|
|
|
info("Set cookies from the service worker in ABA context");
|
|
await setCookiesFromSW(ABABc, [
|
|
"fooABA=barABASW; SameSite=None; Secure",
|
|
"fooABALax=BarABALaxSW; SameSite=Lax; Secure",
|
|
]);
|
|
|
|
info("Get cookies from the service worker in the ABA context.");
|
|
cookieStr = await fetchCookiesFromSW(ABABc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooABA=barABASW",
|
|
"Only the SameSite=None cookie set in ABA service worker is available."
|
|
);
|
|
|
|
await unregisterSW(ABABc);
|
|
BrowserTestUtils.removeTab(tab);
|
|
Services.cookies.removeAll();
|
|
});
|
|
|
|
/**
|
|
* Verify a ABA service worker can only access partitioned cookies set in the
|
|
* ABA context if third-party cookies are blocked.
|
|
*/
|
|
add_task(async function testCookiesWithABAServiceWorker() {
|
|
// Disable blocking third-party cookies.
|
|
await SpecialPowers.pushPrefEnv({
|
|
set: [
|
|
["network.cookie.cookieBehavior.optInPartitioning", true],
|
|
["network.cookie.CHIPS.enabled", true],
|
|
],
|
|
});
|
|
|
|
info("Open a tab");
|
|
let tab = await BrowserTestUtils.openNewForegroundTab(
|
|
gBrowser,
|
|
TEST_TOP_PAGE
|
|
);
|
|
|
|
info("Load a ABA iframe");
|
|
let crossSiteBc = await SpecialPowers.spawn(
|
|
tab.linkedBrowser,
|
|
[TEST_CROSS_SITE_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
let ABABc = await SpecialPowers.spawn(
|
|
crossSiteBc,
|
|
[TEST_TOP_PAGE],
|
|
async url => {
|
|
let ifr = content.document.createElement("iframe");
|
|
|
|
await new content.Promise(resolve => {
|
|
ifr.onload = resolve;
|
|
content.document.body.appendChild(ifr);
|
|
ifr.src = url;
|
|
});
|
|
|
|
return ifr.browsingContext;
|
|
}
|
|
);
|
|
|
|
info("Set cookies in the ABA iframe");
|
|
await SpecialPowers.spawn(ABABc, [], async _ => {
|
|
const cookies = [
|
|
"fooABA=barABA; SameSite=None; Secure",
|
|
"fooABALax=BarABALax; SameSite=Lax; Secure",
|
|
"fooABAPartitioned=barABA; SameSite=None; Secure; Partitioned;",
|
|
"fooABALaxPartitioned=BarABALax; SameSite=Lax; Secure; Partitioned;",
|
|
];
|
|
|
|
let query = "";
|
|
|
|
for (let cookie of cookies) {
|
|
query += `Set-Cookie=${cookie}&`;
|
|
}
|
|
|
|
await content.fetch(`cookies.sjs?${query}`);
|
|
});
|
|
|
|
info(
|
|
"Register a service worker and trigger a fetch request to get cookies in the ABA context."
|
|
);
|
|
|
|
await registerSW(ABABc);
|
|
|
|
info("Get cookies in the ABA service worker.");
|
|
let cookieStr = await fetchCookiesFromSW(ABABc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooABAPartitioned=barABA",
|
|
"Only the SameSite=None partitioned cookie set in ABA iframe is available."
|
|
);
|
|
|
|
info("Set cookies from the service worker in ABA context");
|
|
await setCookiesFromSW(ABABc, [
|
|
"fooABA=barABASW; SameSite=None; Secure",
|
|
"fooABALax=BarABALaxSW; SameSite=Lax; Secure",
|
|
"fooABAPartitioned=barABASW; SameSite=None; Secure; Partitioned;",
|
|
"fooABALaxPartitioned=BarABALaxSW; SameSite=Lax; Secure; Partitioned;",
|
|
]);
|
|
|
|
info("Get cookies from the service worker in the ABA context.");
|
|
cookieStr = await fetchCookiesFromSW(ABABc);
|
|
|
|
is(
|
|
cookieStr,
|
|
"fooABAPartitioned=barABASW",
|
|
"Only the SameSite=None partitioned cookie set in ABA service worker is available."
|
|
);
|
|
|
|
await unregisterSW(ABABc);
|
|
BrowserTestUtils.removeTab(tab);
|
|
Services.cookies.removeAll();
|
|
});
|