Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<meta charset="utf-8">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script src="head.js"></script>
<script>
"use strict";
async function background() {
const firstPartyDomain = "ext-cookie-first-party.mochi.test";
// A first party domain with invalid characters for the file system, which just happens to be a IPv6 address.
const firstPartyDomainInvalidChars = "[2606:4700:4700::1111]";
const expectedError = "First-Party Isolation is enabled, but the required 'firstPartyDomain' attribute was not set.";
const assertExpectedCookies = (expected, cookies, message) => {
let matches = (cookie, expected) => {
if (!cookie || !expected) {
return cookie === expected; // true if both are null.
}
for (let key of Object.keys(expected)) {
if (cookie[key] !== expected[key]) {
return false;
}
}
return true;
};
browser.test.assertEq(expected.length, cookies.length, `Got expected number of cookies - ${message}`);
if (cookies.length !== expected.length) {
return;
}
for (let expect of expected) {
let foundCookies = cookies.filter(cookie => matches(cookie, expect));
browser.test.assertEq(1, foundCookies.length,
`Expected cookie ${JSON.stringify(expect)} found - ${message}`);
}
};
// Test when FPI is disabled.
const test_fpi_disabled = async () => {
let cookie, cookies;
// set
cookie = await browser.cookies.set({url, name: "foo1", value: "bar1"});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "set: FPI off, w/ empty firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.set({url, name: "foo2", value: "bar2", firstPartyDomain});
assertExpectedCookies([
{name: "foo2", value: "bar2", firstPartyDomain},
], [cookie], "set: FPI off, w/ firstPartyDomain, FP cookie");
// get
// When FPI is disabled, missing key/null/undefined is equivalent to "".
cookie = await browser.cookies.get({url, name: "foo1"});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "get: FPI off, w/o firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.get({url, name: "foo1", firstPartyDomain: ""});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "get: FPI off, w/ empty firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.get({url, name: "foo1", firstPartyDomain: null});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "get: FPI off, w/ null firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.get({url, name: "foo1", firstPartyDomain: undefined});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "get: FPI off, w/ undefined firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain});
assertExpectedCookies([
{name: "foo2", value: "bar2", firstPartyDomain},
], [cookie], "get: FPI off, w/ firstPartyDomain, FP cookie");
// There is no match for non-FP cookies with name "foo2".
cookie = await browser.cookies.get({url, name: "foo2"});
assertExpectedCookies([null], [cookie], "get: FPI off, w/o firstPartyDomain, no cookie");
cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain: ""});
assertExpectedCookies([null], [cookie], "get: FPI off, w/ empty firstPartyDomain, no cookie");
cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain: null});
assertExpectedCookies([null], [cookie], "get: FPI off, w/ null firstPartyDomain, no cookie");
cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain: undefined});
assertExpectedCookies([null], [cookie], "get: FPI off, w/ undefined firstPartyDomain, no cookie");
// getAll
for (let extra of [{}, {url}, {domain: firstPartyDomain}]) {
const prefix = `getAll(${JSON.stringify(extra)})`;
cookies = await browser.cookies.getAll({...extra});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], cookies, `${prefix}: FPI off, w/o firstPartyDomain, non-FP cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: ""});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], cookies, `${prefix}: FPI off, w/ empty firstPartyDomain, non-FP cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: null});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
{name: "foo2", value: "bar2", firstPartyDomain},
], cookies, `${prefix}: FPI off, w/ null firstPartyDomain, all cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: undefined});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
{name: "foo2", value: "bar2", firstPartyDomain},
], cookies, `${prefix}: FPI off, w/ undefined firstPartyDomain, all cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain});
assertExpectedCookies([
{name: "foo2", value: "bar2", firstPartyDomain},
], cookies, `${prefix}: FPI off, w/ firstPartyDomain, FP cookies`);
}
// remove
cookie = await browser.cookies.remove({url, name: "foo1"});
assertExpectedCookies([
{url, name: "foo1", firstPartyDomain: ""},
], [cookie], "remove: FPI off, w/ empty firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.remove({url, name: "foo2", firstPartyDomain});
assertExpectedCookies([
{url, name: "foo2", firstPartyDomain},
], [cookie], "remove: FPI off, w/ firstPartyDomain, FP cookie");
// Test if FP cookies set when FPI off can be accessed when FPI on.
await browser.cookies.set({url, name: "foo1", value: "bar1"});
await browser.cookies.set({url, name: "foo2", value: "bar2", firstPartyDomain});
browser.test.sendMessage("test_fpi_disabled");
};
// Test when FPI is enabled.
const test_fpi_enabled = async () => {
let cookie, cookies;
// set
await browser.test.assertRejects(
browser.cookies.set({url, name: "foo3", value: "bar3"}),
expectedError,
"set: FPI on, w/o firstPartyDomain, rejection");
cookie = await browser.cookies.set({url, name: "foo4", value: "bar4", firstPartyDomain});
assertExpectedCookies([
{name: "foo4", value: "bar4", firstPartyDomain},
], [cookie], "set: FPI on, w/ firstPartyDomain, FP cookie");
// get
await browser.test.assertRejects(
browser.cookies.get({url, name: "foo3"}),
expectedError,
"get: FPI on, w/o firstPartyDomain, rejection");
await browser.test.assertRejects(
browser.cookies.get({url, name: "foo3", firstPartyDomain: null}),
expectedError,
"get: FPI on, w/ null firstPartyDomain, rejection");
await browser.test.assertRejects(
browser.cookies.get({url, name: "foo3", firstPartyDomain: undefined}),
expectedError,
"get: FPI on, w/ undefined firstPartyDomain, rejection");
cookie = await browser.cookies.get({url, name: "foo1", firstPartyDomain: ""});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], [cookie], "get: FPI on, w/ empty firstPartyDomain, non-FP cookie");
cookie = await browser.cookies.get({url, name: "foo4", firstPartyDomain});
assertExpectedCookies([
{name: "foo4", value: "bar4", firstPartyDomain},
], [cookie], "get: FPI on, w/ firstPartyDomain, FP cookie");
cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain});
assertExpectedCookies([
{name: "foo2", value: "bar2", firstPartyDomain},
], [cookie], "get: FPI on, w/ firstPartyDomain, FP cookie (set when FPI off)");
// getAll
for (let extra of [{}, {url}, {domain: firstPartyDomain}]) {
const prefix = `getAll(${JSON.stringify(extra)})`;
await browser.test.assertRejects(
browser.cookies.getAll({...extra}),
expectedError,
`${prefix}: FPI on, w/o firstPartyDomain, rejection`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: ""});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
], cookies, `${prefix}: FPI on, w/ empty firstPartyDomain, non-FP cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: null});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
{name: "foo2", value: "bar2", firstPartyDomain},
{name: "foo4", value: "bar4", firstPartyDomain},
], cookies, `${prefix}: FPI on, w/ null firstPartyDomain, all cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain: undefined});
assertExpectedCookies([
{name: "foo1", value: "bar1", firstPartyDomain: ""},
{name: "foo2", value: "bar2", firstPartyDomain},
{name: "foo4", value: "bar4", firstPartyDomain},
], cookies, `${prefix}: FPI on, w/ undefined firstPartyDomain, all cookies`);
cookies = await browser.cookies.getAll({...extra, firstPartyDomain});
assertExpectedCookies([
{name: "foo2", value: "bar2", firstPartyDomain},
{name: "foo4", value: "bar4", firstPartyDomain},
], cookies, `${prefix}: FPI on, w/ firstPartyDomain, FP cookies`);
}
// remove
await browser.test.assertRejects(
browser.cookies.remove({url, name: "foo3"}),
expectedError,
"remove: FPI on, w/o firstPartyDomain, rejection");
cookie = await browser.cookies.remove({url, name: "foo4", firstPartyDomain});
assertExpectedCookies([
{url, name: "foo4", firstPartyDomain},
], [cookie], "remove: FPI on, w/ firstPartyDomain, FP cookie");
cookie = await browser.cookies.remove({url, name: "foo2", firstPartyDomain});
assertExpectedCookies([
{url, name: "foo2", firstPartyDomain},
], [cookie], "remove: FPI on, w/ firstPartyDomain, FP cookie (set when FPI off)");
// Test if FP cookies set when FPI on can be accessed when FPI off.
await browser.cookies.set({url, name: "foo4", value: "bar4", firstPartyDomain});
browser.test.sendMessage("test_fpi_enabled");
};
// Test FPI with a first party domain with invalid characters for
// the file system.
const test_fpi_with_invalid_characters = async () => {
let cookie;
// Test setting a cookie with a first party domain with invalid characters
// for the file system.
cookie = await browser.cookies.set({url, name: "foo5", value: "bar5",
firstPartyDomain: firstPartyDomainInvalidChars});
assertExpectedCookies([
{name: "foo5", value: "bar5", firstPartyDomain: firstPartyDomainInvalidChars},
], [cookie], "set: FPI on, w/ firstPartyDomain with invalid characters, FP cookie");
// Test getting a cookie with a first party domain with invalid characters
// for the file system.
cookie = await browser.cookies.get({url, name: "foo5",
firstPartyDomain: firstPartyDomainInvalidChars});
assertExpectedCookies([
{name: "foo5", value: "bar5", firstPartyDomain: firstPartyDomainInvalidChars},
], [cookie], "get: FPI on, w/ firstPartyDomain with invalid characters, FP cookie");
// Test removing a cookie with a first party domain with invalid characters
// for the file system.
cookie = await browser.cookies.remove({url, name: "foo5",
firstPartyDomain: firstPartyDomainInvalidChars});
assertExpectedCookies([
{url, name: "foo5", firstPartyDomain: firstPartyDomainInvalidChars},
], [cookie], "remove: FPI on, w/ firstPartyDomain with invalid characters, FP cookie");
browser.test.sendMessage("test_fpi_with_invalid_characters");
};
// Test when FPI is disabled again, accessing FP cookies set when FPI is enabled.
const test_fpd_cookies_on_fpi_disabled = async () => {
let cookie, cookies;
cookie = await browser.cookies.get({url, name: "foo4", firstPartyDomain});
assertExpectedCookies([
{name: "foo4", value: "bar4", firstPartyDomain},
], [cookie], "get: FPI off, w/ firstPartyDomain, FP cookie (set when FPI on)");
cookie = await browser.cookies.remove({url, name: "foo4", firstPartyDomain});
assertExpectedCookies([
{url, name: "foo4", firstPartyDomain},
], [cookie], "remove: FPI off, w/ firstPartyDomain, FP cookie (set when FPI on)");
// Clean up.
await browser.cookies.remove({url, name: "foo1"});
cookies = await browser.cookies.getAll({firstPartyDomain: null});
assertExpectedCookies([], cookies, "Test is finishing, all cookies removed");
browser.test.sendMessage("test_fpd_cookies_on_fpi_disabled");
};
browser.test.onMessage.addListener((message) => {
switch (message) {
case "test_fpi_disabled": return test_fpi_disabled();
case "test_fpi_enabled": return test_fpi_enabled();
case "test_fpi_with_invalid_characters": return test_fpi_with_invalid_characters();
case "test_fpd_cookies_on_fpi_disabled": return test_fpd_cookies_on_fpi_disabled();
default: return browser.test.notifyFail("unknown-message");
}
});
}
function enableFirstPartyIsolation() {
return SpecialPowers.pushPrefEnv({
set: [
["privacy.firstparty.isolate", true],
],
});
}
function disableFirstPartyIsolation() {
return SpecialPowers.popPrefEnv();
}
add_task(async () => {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["cookies", "*://ext-cookie-first-party.mochi.test/"],
},
});
await extension.startup();
extension.sendMessage("test_fpi_disabled");
await extension.awaitMessage("test_fpi_disabled");
await enableFirstPartyIsolation();
extension.sendMessage("test_fpi_enabled");
await extension.awaitMessage("test_fpi_enabled");
extension.sendMessage("test_fpi_with_invalid_characters");
await extension.awaitMessage("test_fpi_with_invalid_characters");
await disableFirstPartyIsolation();
extension.sendMessage("test_fpd_cookies_on_fpi_disabled");
await extension.awaitMessage("test_fpd_cookies_on_fpi_disabled");
await extension.unload();
});
</script>