"use strict"; /** * Bug 1933428 - Ensure that we don't hit the invalid first-party cookie * assertion when loading a channel which sets a cookie in sandboxed contexts. */ const TEST_SITE = "https://example.com/"; const TEST_SANDBOXED_PAGE = TEST_SITE + TEST_PATH + "sandboxedWithImg.html"; const TEST_IMAGE_URL = TEST_SITE + TEST_PATH + "setCookieImg.jpg"; /** * Observes the channel for the given URL and checks if it is in the third-party * context and verifies the partition key. * * @param {string} url - The URL to observe. * @param {boolean} isThirdParty - Whether the request is in the third-party context. * @param {boolean} isPartitionKeyOpaque - Whether the partition key is using an opaque origin. * @param {string} partitionKey - The partition key to check for. * @returns {Promise} Resolves when the channel is observed. */ function observeChannel(url, isThirdParty, isPartitionKeyOpaque, partitionKey) { return new Promise(resolve => { let observer = { observe(aSubject, aTopic) { // Make sure that the topic is 'http-on-modify-request'. if (aTopic === "http-on-modify-request") { let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); // Make sure this is the request we're looking for. if (httpChannel.URI.spec !== url) { return; } let loadInfo = httpChannel.loadInfo; if (isPartitionKeyOpaque) { ok( loadInfo.cookieJarSettings.partitionKey.endsWith(".mozilla"), "The partition key is using an opaque origin" ); } else { is( loadInfo.cookieJarSettings.partitionKey, partitionKey, "The partition key is correct" ); } is( loadInfo.isInThirdPartyContext, isThirdParty, `The request ${ isThirdParty ? "is" : "is not" } in the third-party context` ); Services.obs.removeObserver(observer, "http-on-modify-request"); resolve(); } }, }; Services.obs.addObserver(observer, "http-on-modify-request"); }); } add_setup(async function () { registerCleanupFunction(() => { Services.cookies.removeAll(); }); }); add_task(async function test_top_level_sandboxed_context() { // Start observing the channel before opening the tab. The image should be // loaded in the first-party context. let obsChannelPromise = observeChannel(TEST_IMAGE_URL, false, true); Services.cookies.removeAll(); info("Opening the top-level sandboxed page"); let tab = await BrowserTestUtils.openNewForegroundTab( gBrowser, TEST_SANDBOXED_PAGE ); await obsChannelPromise; ok(true, "The loading of the image was successful."); is(Services.cookies.cookies.length, 1, "The cookie was set"); is( Services.cookies.cookies[0].isSession, true, "The cookie is forced to be a session cookie" ); BrowserTestUtils.removeTab(tab); }); add_task(async function test_sandboxed_iframe() { Services.cookies.removeAll(); info("Opening the top-level page"); let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_SITE); // Start observing the channel before opening the iframe. The image should be // loaded in the third-party context and the partition key should have the // foreign ancestor bit set. let obsChannelPromise = observeChannel( TEST_IMAGE_URL, true, false, "(https,example.com,f)" ); info(" Loading the sandboxed iframe"); await SpecialPowers.spawn( tab.linkedBrowser, [TEST_SANDBOXED_PAGE], async src => { let iframe = content.document.createElement("iframe"); await new Promise(resolve => { iframe.onload = resolve; iframe.src = src; content.document.body.appendChild(iframe); }); return iframe.browsingContext; } ); await obsChannelPromise; ok(true, "The loading of the image in the sandboxed iframe was successful."); is(Services.cookies.cookies.length, 1, "The cookie was set"); is( Services.cookies.cookies[0].isSession, false, "The cookie isn't forced to be a session cookie" ); BrowserTestUtils.removeTab(tab); });