1
0
Fork 0
firefox/toolkit/components/cleardata/tests/browser/browser_sessionStorage.js
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

312 lines
9.5 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const BASE_DOMAIN_A = "example.com";
const ORIGIN_A = `https://${BASE_DOMAIN_A}`;
const ORIGIN_A_HTTP = `http://${BASE_DOMAIN_A}`;
const ORIGIN_A_SUB = `https://test1.${BASE_DOMAIN_A}`;
const BASE_DOMAIN_B = "example.org";
const ORIGIN_B = `https://${BASE_DOMAIN_B}`;
const ORIGIN_B_HTTP = `http://${BASE_DOMAIN_B}`;
const ORIGIN_B_SUB = `https://test1.${BASE_DOMAIN_B}`;
const TEST_ROOT_DIR = getRootDirectory(gTestPath);
// Session storage is only valid for the lifetime of a tab, so we need to keep
// tabs open for the duration of a test.
let originToTabs = {};
function getTestURLForOrigin(origin) {
return TEST_ROOT_DIR.replace("chrome://mochitests/content", origin);
}
function getTestEntryName(origin, partitioned) {
return `${origin}${partitioned ? "_partitioned" : ""}`;
}
async function testHasEntry(
originFirstParty,
isSet,
originThirdParty,
originAttributes = { userContextId: 0 }
) {
// Get all matching tabs for this origin
let tabs = originToTabs[originFirstParty];
if (!tabs) {
return;
}
// Filter tabs by userContextId if specified
let relevantTabs = tabs;
if (originAttributes.userContextId !== undefined) {
relevantTabs = tabs.filter(
tab => tab.userContextId === originAttributes.userContextId
);
}
for (let tab of relevantTabs) {
// For the partition test we inspect the sessionStorage of the iframe.
let browsingContext = originThirdParty
? tab.linkedBrowser.browsingContext.children[0]
: tab.linkedBrowser.browsingContext;
let actualSet = await SpecialPowers.spawn(
browsingContext,
[
getTestEntryName(
originThirdParty || originFirstParty,
!!originThirdParty
),
],
key => {
return !!content.sessionStorage.getItem(key);
}
);
let msg = `${originFirstParty}${isSet ? " " : " not "}set`;
if (originThirdParty) {
msg = "Partitioned under " + msg;
}
if (tab.userContextId) {
msg += ` (userContextId: ${tab.userContextId})`;
}
is(actualSet, isSet, msg);
}
}
/**
* Creates tabs and sets sessionStorage entries in first party and third party
* context.
* @returns {Promise} - Promise which resolves once all tabs are initialized,
* {@link originToTabs} is populated and (sub-)resources have loaded.
*/
function addTestTabs() {
let promises = [
[ORIGIN_A, ORIGIN_B],
[ORIGIN_A_SUB, ORIGIN_B_SUB],
[ORIGIN_A_HTTP, ORIGIN_B_HTTP],
[ORIGIN_B, ORIGIN_A],
[ORIGIN_B_SUB, ORIGIN_A_SUB],
[ORIGIN_B_HTTP, ORIGIN_A_HTTP],
[ORIGIN_A, ORIGIN_B, 1],
].map(async ([firstParty, thirdParty, userContextId]) => {
info(
`Creating new tab for ${firstParty}, userContextId: ${userContextId ?? 0}`
);
let tab = BrowserTestUtils.addTab(gBrowser, firstParty, { userContextId });
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
info(`Creating iframe for ${thirdParty}`);
await SpecialPowers.spawn(
tab.linkedBrowser,
[getTestEntryName(firstParty, false), thirdParty],
async (storageKey, url) => {
// Set unpartitioned sessionStorage for firstParty.
content.sessionStorage.setItem(storageKey, "foo");
let iframe = content.document.createElement("iframe");
iframe.src = url;
let loadPromise = ContentTaskUtils.waitForEvent(iframe, "load", false);
content.document.body.appendChild(iframe);
await loadPromise;
}
);
await SpecialPowers.spawn(
tab.linkedBrowser.browsingContext.children[0],
[getTestEntryName(thirdParty, true)],
async storageKey => {
// Set sessionStorage in partitioned third-party iframe.
content.sessionStorage.setItem(storageKey, "foo");
}
);
let tabs = originToTabs[firstParty];
if (!tabs) {
tabs = [];
originToTabs[firstParty] = tabs;
}
tabs.push(tab);
});
return Promise.all(promises);
}
function cleanup() {
Object.values(originToTabs).flat().forEach(BrowserTestUtils.removeTab);
originToTabs = {};
Services.obs.notifyObservers(null, "browser:purge-sessionStorage");
}
add_setup(async function () {
await SpecialPowers.pushPrefEnv({
set: [["network.cookie.cookieBehavior", 5]],
});
cleanup();
});
add_task(async function test_deleteDataFromSite() {
await addTestTabs();
info("Clearing sessionStorage for base domain A " + BASE_DOMAIN_A);
await new Promise(resolve => {
Services.clearData.deleteDataFromSite(
BASE_DOMAIN_A,
{},
false,
Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
resolve
);
});
info("All entries for A should have been cleared.");
await testHasEntry(ORIGIN_A, false);
await testHasEntry(ORIGIN_A, false, null, { userContextId: 1 });
await testHasEntry(ORIGIN_A_SUB, false);
await testHasEntry(ORIGIN_A_HTTP, false);
info("Entries for B should still exist.");
await testHasEntry(ORIGIN_B, true);
await testHasEntry(ORIGIN_B_SUB, true);
await testHasEntry(ORIGIN_B_HTTP, true);
info("All partitioned entries for B under A should have been cleared.");
await testHasEntry(ORIGIN_A, false, ORIGIN_B);
await testHasEntry(ORIGIN_A, false, ORIGIN_B, { userContextId: 1 });
await testHasEntry(ORIGIN_A_SUB, false, ORIGIN_B_SUB);
await testHasEntry(ORIGIN_A_HTTP, false, ORIGIN_B_HTTP);
info("All partitioned entries of A under B should have been cleared.");
await testHasEntry(ORIGIN_B, false, ORIGIN_A);
await testHasEntry(ORIGIN_B, false, ORIGIN_A, { userContextId: 1 });
await testHasEntry(ORIGIN_B_SUB, false, ORIGIN_A_SUB);
await testHasEntry(ORIGIN_B_HTTP, false, ORIGIN_A_HTTP);
cleanup();
});
add_task(async function test_deleteDataFromSiteAndPattern() {
await addTestTabs();
let pattern = {
userContextId: 1,
};
info(
`Clearing sessionStorage for base domain A ${BASE_DOMAIN_A} with pattern ${JSON.stringify(pattern)}.`
);
await new Promise(resolve => {
Services.clearData.deleteDataFromSite(
BASE_DOMAIN_A,
pattern,
false,
Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
resolve
);
});
info("Only entries for A that match the pattern should have been cleared.");
await testHasEntry(ORIGIN_A, true);
await testHasEntry(ORIGIN_A, false, null, { userContextId: 1 });
await testHasEntry(ORIGIN_A_SUB, true);
await testHasEntry(ORIGIN_A_HTTP, true);
info("Entries for B should still exist.");
await testHasEntry(ORIGIN_B, true);
await testHasEntry(ORIGIN_B_SUB, true);
await testHasEntry(ORIGIN_B_HTTP, true);
info(
"All partitioned entries for B under A which match the pattern should have been cleared."
);
await testHasEntry(ORIGIN_A, true, ORIGIN_B);
await testHasEntry(ORIGIN_A, false, ORIGIN_B, { userContextId: 1 });
await testHasEntry(ORIGIN_A_SUB, true, ORIGIN_B_SUB);
await testHasEntry(ORIGIN_A_HTTP, true, ORIGIN_B_HTTP);
info(
"All partitioned entries of A under B which match the pattern should have been cleared."
);
await testHasEntry(ORIGIN_B, true, ORIGIN_A);
await testHasEntry(ORIGIN_B, false, ORIGIN_A, { userContextId: 1 });
await testHasEntry(ORIGIN_B_SUB, true, ORIGIN_A_SUB);
await testHasEntry(ORIGIN_B_HTTP, true, ORIGIN_A_HTTP);
cleanup();
});
add_task(async function test_deleteAll() {
await addTestTabs();
info("Clearing sessionStorage for base domain A " + BASE_DOMAIN_A);
await new Promise(resolve => {
Services.clearData.deleteData(
Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
resolve
);
});
info("All entries should have been cleared.");
await testHasEntry(ORIGIN_A, false);
await testHasEntry(ORIGIN_A_SUB, false);
await testHasEntry(ORIGIN_A_HTTP, false);
await testHasEntry(ORIGIN_B, false);
await testHasEntry(ORIGIN_B_SUB, false);
await testHasEntry(ORIGIN_B_HTTP, false);
info("All partitioned entries should have been cleared.");
await testHasEntry(ORIGIN_A, false, ORIGIN_B);
await testHasEntry(ORIGIN_A_SUB, false, ORIGIN_B_SUB);
await testHasEntry(ORIGIN_A_HTTP, false, ORIGIN_B_HTTP);
await testHasEntry(ORIGIN_B, false, ORIGIN_A);
await testHasEntry(ORIGIN_B_SUB, false, ORIGIN_A_SUB);
await testHasEntry(ORIGIN_B_HTTP, false, ORIGIN_A_HTTP);
cleanup();
});
add_task(async function test_deleteFromPrincipal() {
await addTestTabs();
info("Clearing sessionStorage for partitioned principal A " + BASE_DOMAIN_A);
let principalA = Services.scriptSecurityManager.createContentPrincipal(
Services.io.newURI(ORIGIN_A),
{ partitionKey: `(https,${BASE_DOMAIN_B})` }
);
info("principal: " + principalA.origin);
info("principal partitionKey " + principalA.originAttributes.partitionKey);
await new Promise(resolve => {
Services.clearData.deleteDataFromPrincipal(
principalA,
false,
Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
resolve
);
});
info("Unpartitioned entries should still exist.");
await testHasEntry(ORIGIN_A, true);
await testHasEntry(ORIGIN_A_SUB, true);
await testHasEntry(ORIGIN_A_HTTP, true);
await testHasEntry(ORIGIN_B, true);
await testHasEntry(ORIGIN_B_SUB, true);
await testHasEntry(ORIGIN_B_HTTP, true);
info("Only entries of principal should have been cleared.");
await testHasEntry(ORIGIN_A, true, ORIGIN_B);
await testHasEntry(ORIGIN_A_SUB, true, ORIGIN_B_SUB);
await testHasEntry(ORIGIN_A_HTTP, true, ORIGIN_B_HTTP);
await testHasEntry(ORIGIN_B, false, ORIGIN_A);
await testHasEntry(ORIGIN_B_SUB, true, ORIGIN_A_SUB);
await testHasEntry(ORIGIN_B_HTTP, true, ORIGIN_A_HTTP);
cleanup();
});