diff options
Diffstat (limited to 'netwerk/cookie/test/browser/browser_cookie_chips.js')
-rw-r--r-- | netwerk/cookie/test/browser/browser_cookie_chips.js | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/netwerk/cookie/test/browser/browser_cookie_chips.js b/netwerk/cookie/test/browser/browser_cookie_chips.js new file mode 100644 index 0000000000..ba0c8f3a0e --- /dev/null +++ b/netwerk/cookie/test/browser/browser_cookie_chips.js @@ -0,0 +1,539 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_setup(() => { + // These are functional and not integration tests, cookieBehavior accept lets + // us have StorageAccess on thirparty. + Services.prefs.setIntPref( + "network.cookie.cookieBehavior", + Ci.nsICookieService.BEHAVIOR_ACCEPT + ); + Services.prefs.setBoolPref( + "network.cookieJarSettings.unblocked_for_testing", + true + ); + Services.prefs.setBoolPref( + "network.cookie.cookieBehavior.optInPartitioning", + true + ); + Services.prefs.setBoolPref("dom.storage_access.enabled", true); + Services.prefs.setBoolPref("dom.storage_access.prompt.testing", true); + Services.cookies.removeAll(); + Services.perms.removeAll(); +}); + +registerCleanupFunction(() => { + Services.prefs.clearUserPref("network.cookie.cookieBehavior"); + Services.prefs.clearUserPref( + "network.cookieJarSettings.unblocked_for_testing" + ); + Services.prefs.clearUserPref( + "network.cookie.cookieBehavior.optInPartitioning" + ); + Services.prefs.clearUserPref("dom.storage_access.enabled"); + Services.prefs.clearUserPref("dom.storage_access.prompt.testing"); + Services.cookies.removeAll(); + Services.perms.removeAll(); +}); + +const COOKIE_PARTITIONED = + "cookie=partitioned; Partitioned; Secure; SameSite=None;"; +const COOKIE_UNPARTITIONED = "cookie=unpartitioned; Secure; SameSite=None;"; + +const PATH = "/browser/netwerk/cookie/test/browser/"; +const PATH_EMPTY = PATH + "file_empty.html"; +const HTTP_COOKIE_SET = PATH + "chips.sjs?set"; +const HTTP_COOKIE_GET = PATH + "chips.sjs?get"; + +const FIRST_PARTY = "example.com"; +const THIRD_PARTY = "example.org"; + +const URL_DOCUMENT_FIRSTPARTY = "https://" + FIRST_PARTY + PATH_EMPTY; +const URL_DOCUMENT_THIRDPARTY = "https://" + THIRD_PARTY + PATH_EMPTY; +const URL_HTTP_FIRSTPARTY = "https://" + FIRST_PARTY + "/" + HTTP_COOKIE_SET; +const URL_HTTP_THIRDPARTY = "https://" + THIRD_PARTY + "/" + HTTP_COOKIE_SET; + +function createOriginAttributes(partitionKey) { + return JSON.stringify({ + firstPartyDomain: "", + geckoViewSessionContextId: "", + inIsolatedMozBrowser: false, + partitionKey, + privateBrowsingId: 0, + userContextId: 0, + }); +} + +function createPartitonKey(url) { + let uri = NetUtil.newURI(url); + return `(${uri.scheme},${uri.host})`; +} + +// OriginAttributes used to access partitioned and unpartitioned cookie jars +// in all tests. +const partitionedOAs = createOriginAttributes( + createPartitonKey(URL_DOCUMENT_FIRSTPARTY) +); +const unpartitionedOAs = createOriginAttributes(""); + +// Set partitioned and unpartitioned cookie from first-party document. +// CHIPS "Partitioned" cookie MUST always be stored in partitioned jar. +// This calls CookieServiceChild::SetCookieStringFromDocument() internally. +// CookieService::SetCookieStringFromDocument() is not explicitly tested since +// CHIPS are in the common function CookieCommons::CreateCookieFromDocument(). +add_task( + async function test_chips_store_partitioned_document_first_party_child() { + const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Set partitioned and unpartitioned cookie from document child-side + await SpecialPowers.spawn( + browser, + [COOKIE_PARTITIONED, COOKIE_UNPARTITIONED], + (partitioned, unpartitioned) => { + content.document.cookie = partitioned; + content.document.cookie = unpartitioned; + } + ); + + // Get cookies from partitioned jar + let partitioned = Services.cookies.getCookiesWithOriginAttributes( + partitionedOAs, + FIRST_PARTY + ); + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + FIRST_PARTY + ); + + // Assert partitioned/unpartitioned cookie were stored in correct jars + Assert.equal(partitioned.length, 1); + Assert.equal(partitioned[0].value, "partitioned"); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + } +); + +// Set partitioned and unpartitioned cookie from third-party document with storage +// access. CHIPS "Partitioned" cookie MUST always be stored in partitioned jar. +// This calls CookieServiceChild::SetCookieStringFromDocument() internally. +// CookieService::SetCookieStringFromDocument() is not explicitly tested since +// CHIPS are in the common function CookieCommons::CreateCookieFromDocument(). +add_task( + async function test_chips_store_partitioned_document_third_party_storage_access_child() { + const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Spawn document bc + await SpecialPowers.spawn( + browser, + [URL_DOCUMENT_THIRDPARTY, COOKIE_PARTITIONED, COOKIE_UNPARTITIONED], + async (url, partitioned, unpartitioned) => { + let ifr = content.document.createElement("iframe"); + ifr.src = url; + content.document.body.appendChild(ifr); + await ContentTaskUtils.waitForEvent(ifr, "load"); + + // Spawn iframe bc + await SpecialPowers.spawn( + await ifr.browsingContext, + [partitioned, unpartitioned], + async (partitioned, unpartitioned) => { + ok( + await content.document.hasStorageAccess(), + "example.org should have storageAccess by CookieBehavior 0 / test setup" + ); + + content.document.cookie = partitioned; + content.document.cookie = unpartitioned; + } + ); + } + ); + + // Get cookies from partitioned jar + let partitioned = Services.cookies.getCookiesWithOriginAttributes( + partitionedOAs, + THIRD_PARTY + ); + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + THIRD_PARTY + ); + + // Assert partitioned/unpartitioned cookie were stored in correct jars + Assert.equal(partitioned.length, 1); + Assert.equal(partitioned[0].value, "partitioned"); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + } +); + +// Set partitioned and unpartitioned cookie from first-party http load. +// CHIPS "Partitioned" cookie MUST always be stored in partitioned jar. +// This calls CookieService::SetCookieStringFromHttp() internally. +add_task(async function test_chips_store_partitioned_http_first_party_parent() { + // Set partitioned and unpartitioned cookie from http parent side through + // chips.sjs being loaded. + const tab = BrowserTestUtils.addTab(gBrowser, URL_HTTP_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Get cookies from partitioned jar + let partitioned = Services.cookies.getCookiesWithOriginAttributes( + partitionedOAs, + FIRST_PARTY + ); + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + FIRST_PARTY + ); + + // Assert partitioned/unpartitioned cookie were stored in correct jars + Assert.equal(partitioned.length, 1); + Assert.equal(partitioned[0].value, "partitioned"); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); +}); + +// Set partitioned and unpartitioned cookie from third-party http load. +// CHIPS "Partitioned" cookie MUST always be stored in partitioned jar. +// This calls CookieService::SetCookieStringFromHttp() internally. +add_task( + async function test_chips_store_partitioned_http_third_party_storage_access_parent() { + const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Spawn document bc + await SpecialPowers.spawn(browser, [URL_HTTP_THIRDPARTY], async url => { + let ifr = content.document.createElement("iframe"); + ifr.src = url; + content.document.body.appendChild(ifr); + // Send http request with "set" query parameter, partitioned and + // unpartitioned cookie will be set through http response from chips.sjs. + await ContentTaskUtils.waitForEvent(ifr, "load"); + + // Spawn iframe bc + await SpecialPowers.spawn(await ifr.browsingContext, [], async () => { + ok( + await content.document.hasStorageAccess(), + "example.org should have storageAccess by CookieBehavior 0 / test setup" + ); + }); + }); + + // Get cookies from partitioned jar + let partitioned = Services.cookies.getCookiesWithOriginAttributes( + partitionedOAs, + THIRD_PARTY + ); + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + THIRD_PARTY + ); + + // Assert partitioned/unpartitioned cookie were stored in correct jars + Assert.equal(partitioned.length, 1); + Assert.equal(partitioned[0].value, "partitioned"); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + } +); + +// TODO CHIPS - Tests for CookieServiceChild::SetCookieStringFromHttp() need +// to be added. Since this is only checkable on onProxyConnectSuccess needs +// proxy setup test harness. It is also called after onStartRequest() (Http) +// but cookies are already set by the parents +// CookieService::SetCookieStringFromHttp() call. + +// Get partitioned and unpartitioned cookies from document (child). +// This calls CookieServiceChild::GetCookieStringFromDocument() internally. +add_task( + async function test_chips_send_partitioned_and_unpartitioned_document_child() { + const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Spawn document bc + await SpecialPowers.spawn( + browser, + [COOKIE_PARTITIONED, COOKIE_UNPARTITIONED], + async (partitioned, unpartitioned) => { + content.document.cookie = partitioned; + content.document.cookie = unpartitioned; + + // Assert both unpartitioned and partitioned cookie are returned. + let cookies = content.document.cookie; + ok( + cookies.includes("cookie=partitioned"), + "Cookie from partitioned jar was sent." + ); + ok( + cookies.includes("cookie=unpartitioned"), + "Cookie from unpartitioned jar was sent." + ); + } + ); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + } +); + +// Get partitioned and unpartitioned cookies from document (child) after +// storageAccess was granted. This calls CookieServiceChild::TrackCookieLoad() +// internally to update child's cookies. +add_task( + async function test_chips_send_partitioned_and_unpartitioned_on_storage_access_child() { + // Set cookieBehavior to BEHAVIOR_REJECT_TRACKERS_AND_PARTITION_FOREIGN for + // requestStorageAccess() based test. + Services.prefs.setIntPref("network.cookie.cookieBehavior", 5); + + // Set example.org first-party unpartitioned cookie + await BrowserTestUtils.withNewTab( + URL_DOCUMENT_THIRDPARTY, + async browser => { + info("Set a first party cookie via `document.cookie`."); + await SpecialPowers.spawn( + browser, + [COOKIE_UNPARTITIONED], + async unpartitioned => { + content.document.cookie = unpartitioned; + is( + content.document.cookie, + "cookie=unpartitioned", + "Unpartitioned cookie was set." + ); + } + ); + } + ); + + // Assert cookie was set on parent cookie service for example.org. + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + THIRD_PARTY + ); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Load example.com as first-party in tab + const tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + const browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + // Set third-party cookie from example.org iframe, get storageAccess and + // check cookies. + // Spawn document bc + await SpecialPowers.spawn( + browser, + [URL_DOCUMENT_THIRDPARTY, COOKIE_PARTITIONED], + async (url, partitioned) => { + // Create third-party iframe + let ifr = content.document.createElement("iframe"); + ifr.src = url; + content.document.body.appendChild(ifr); + await ContentTaskUtils.waitForEvent(ifr, "load"); + + // Spawn iframe bc + await SpecialPowers.spawn( + await ifr.browsingContext, + [partitioned], + async partitioned => { + ok( + !(await content.document.hasStorageAccess()), + "example.org should not have storageAccess initially." + ); + + // Set a partitioned third-party cookie and assert its the only. + content.document.cookie = partitioned; + is( + content.document.cookie, + "cookie=partitioned", + "Partitioned cookie was set." + ); + + info("Simulate user activation."); + SpecialPowers.wrap(content.document).notifyUserGestureActivation(); + + info("Request storage access."); + await content.document.requestStorageAccess(); + + ok( + await content.document.hasStorageAccess(), + "example.org should now have storageAccess." + ); + + // Assert both unpartitioned and partitioned cookie are returned. + let cookies = content.document.cookie; + ok( + cookies.includes("cookie=partitioned"), + "Cookie from partitioned jar was sent." + ); + ok( + cookies.includes("cookie=unpartitioned"), + "Cookie from unpartitioned jar was sent." + ); + } + ); + } + ); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + Services.perms.removeAll(); + Services.prefs.setIntPref("network.cookie.cookieBehavior", 0); + } +); + +// Set partitioned and unpartitioned cookies for URL_DOCUMENT_FIRSTPARTY, then +// load URL again, assure cookies are correctly send to content child process. +// This tests CookieServiceParent::TrackCookieLoad() internally. +add_task( + async function test_chips_send_partitioned_and_unpartitioned_document_parent() { + // Set example.com first-party unpartitioned and partitioned cookie, then + // close tab. + await BrowserTestUtils.withNewTab( + URL_DOCUMENT_FIRSTPARTY, + async browser => { + await SpecialPowers.spawn( + browser, + [COOKIE_PARTITIONED, COOKIE_UNPARTITIONED], + async (partitioned, unpartitioned) => { + content.document.cookie = unpartitioned; + content.document.cookie = partitioned; + let cookies = content.document.cookie; + ok( + cookies.includes("cookie=unpartitioned"), + "Unpartitioned cookie was set." + ); + ok( + cookies.includes("cookie=partitioned"), + "Partitioned cookie was set." + ); + } + ); + } + ); + + // Assert we have one partitioned and one unpartitioned cookie set. + // Get cookies from partitioned jar + let partitioned = Services.cookies.getCookiesWithOriginAttributes( + partitionedOAs, + FIRST_PARTY + ); + // Get cookies from unpartitioned jar + let unpartitioned = Services.cookies.getCookiesWithOriginAttributes( + unpartitionedOAs, + FIRST_PARTY + ); + Assert.equal(partitioned.length, 1); + Assert.equal(partitioned[0].value, "partitioned"); + Assert.equal(unpartitioned.length, 1); + Assert.equal(unpartitioned[0].value, "unpartitioned"); + + // Reload example.com and assert previously set cookies are correctly + // send to content child document. + await BrowserTestUtils.withNewTab( + URL_DOCUMENT_FIRSTPARTY, + async browser => { + await SpecialPowers.spawn(browser, [], () => { + let cookies = content.document.cookie; + ok( + cookies.includes("cookie=unpartitioned"), + "Unpartitioned cookie was sent." + ); + ok( + cookies.includes("cookie=partitioned"), + "Partitioned cookie was sent." + ); + }); + } + ); + + // Cleanup + Services.cookies.removeAll(); + } +); + +// Set partitioned and unpartitioned cookies for URL_DOCUMENT_FIRSTPARTY, then +// send http request, assure cookies are correctly send in "Cookie" header. +// This tests CookieService::GetCookieStringFromHttp() internally. +add_task( + async function test_chips_send_partitioned_and_unpartitioned_http_parent() { + // Load empty document. + let tab = BrowserTestUtils.addTab(gBrowser, URL_DOCUMENT_FIRSTPARTY); + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + await SpecialPowers.spawn( + browser, + [HTTP_COOKIE_SET, HTTP_COOKIE_GET], + async (set, get) => { + // Send http request with "set" query parameter, partitioned and + // unpartitioned cookie will be set through http response. + await content.fetch(set); + + // Assert cookies were set to document. + let cookies = content.document.cookie; + ok( + cookies.includes("cookie=unpartitioned"), + "Unpartitioned cookie was set to document." + ); + ok( + cookies.includes("cookie=partitioned"), + "Partitioned cookie was set to document." + ); + + // Send http request with "get" query parameter, chips.sjs will return + // the request "Cookie" header string. + await content + .fetch(get) + .then(response => response.text()) + .then(requestCookies => { + // Assert cookies were sent in http request. + ok( + requestCookies.includes("cookie=unpartitioned"), + "Unpartitioned cookie was sent in http request." + ); + ok( + requestCookies.includes("cookie=partitioned"), + "Partitioned cookie was sent in http request." + ); + }); + } + ); + + // Cleanup + BrowserTestUtils.removeTab(tab); + Services.cookies.removeAll(); + } +); |