Bug 1705029 - Added CookieCleaner deleteByBaseDomain. r=johannh,preferences-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D113496
This commit is contained in:
Paul Zuehlcke 2021-05-26 13:49:37 +00:00
Родитель cb8ac7af93
Коммит 550c3ecf40
13 изменённых файлов: 433 добавлений и 60 удалений

Просмотреть файл

@ -308,9 +308,21 @@ add_task(async function test_SiteData() {
// Test displaying and removing cookies.
add_task(async function test_Cookies() {
// Add some test cookies.
SiteDataTestUtils.addToCookies(TEST_ORIGIN, "test1", "1");
SiteDataTestUtils.addToCookies(TEST_ORIGIN, "test2", "2");
SiteDataTestUtils.addToCookies(TEST_SUB_ORIGIN, "test1", "1");
SiteDataTestUtils.addToCookies({
origin: TEST_ORIGIN,
name: "test1",
value: "1",
});
SiteDataTestUtils.addToCookies({
origin: TEST_ORIGIN,
name: "test2",
value: "2",
});
SiteDataTestUtils.addToCookies({
origin: TEST_SUB_ORIGIN,
name: "test1",
value: "1",
});
await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function(browser) {
let pageInfo = BrowserPageInfo(TEST_ORIGIN, "securityTab");

Просмотреть файл

@ -28,7 +28,7 @@ add_task(async function subDomains1() {
Ci.nsICookiePermission.ACCESS_SESSION
);
SiteDataTestUtils.addToCookies(originA);
SiteDataTestUtils.addToCookies({ origin: originA });
await SiteDataTestUtils.addToIndexedDB(originA);
let originB = "https://mozilla.org";
@ -38,7 +38,7 @@ add_task(async function subDomains1() {
Ci.nsICookiePermission.ACCESS_ALLOW
);
SiteDataTestUtils.addToCookies(originB);
SiteDataTestUtils.addToCookies({ origin: originB });
await SiteDataTestUtils.addToIndexedDB(originB);
// Check
@ -101,12 +101,12 @@ add_task(async function subDomains2() {
Ci.nsICookiePermission.ACCESS_ALLOW
);
SiteDataTestUtils.addToCookies(originA);
SiteDataTestUtils.addToCookies({ origin: originA });
await SiteDataTestUtils.addToIndexedDB(originA);
let originB = "https://www.mozilla.org";
SiteDataTestUtils.addToCookies(originB);
SiteDataTestUtils.addToCookies({ origin: originB });
await SiteDataTestUtils.addToIndexedDB(originB);
// Check
@ -170,15 +170,15 @@ add_task(async function subDomains3() {
"cookie",
Ci.nsICookiePermission.ACCESS_ALLOW
);
SiteDataTestUtils.addToCookies(originA);
SiteDataTestUtils.addToCookies({ origin: originA });
await SiteDataTestUtils.addToIndexedDB(originA);
let originB = "https://mozilla.org";
SiteDataTestUtils.addToCookies(originB);
SiteDataTestUtils.addToCookies({ origin: originB });
await SiteDataTestUtils.addToIndexedDB(originB);
let originC = "https://www.mozilla.org";
SiteDataTestUtils.addToCookies(originC);
SiteDataTestUtils.addToCookies({ origin: originC });
await SiteDataTestUtils.addToIndexedDB(originC);
// Check

Просмотреть файл

@ -9,7 +9,7 @@ add_task(async function sanitizeStorageAccessPermissions() {
});
await SiteDataTestUtils.addToIndexedDB("https://sub.example.org");
await SiteDataTestUtils.addToCookies("https://example.com");
await SiteDataTestUtils.addToCookies({ origin: "https://example.com" });
PermissionTestUtils.add(
"https://example.org",

Просмотреть файл

@ -33,9 +33,21 @@ async function testClearing(
// Add some test cookies.
if (testCookies) {
SiteDataTestUtils.addToCookies(origin, "test1", "1");
SiteDataTestUtils.addToCookies(origin, "test2", "2");
SiteDataTestUtils.addToCookies(subOrigin, "test3", "1");
SiteDataTestUtils.addToCookies({
origin,
name: "test1",
value: "1",
});
SiteDataTestUtils.addToCookies({
origin,
name: "test2",
value: "2",
});
SiteDataTestUtils.addToCookies({
origin: subOrigin,
name: "test3",
value: "1",
});
}
await BrowserTestUtils.withNewTab(testURI, async function(browser) {

Просмотреть файл

@ -200,6 +200,10 @@ function assertSitesListed(doc, hosts) {
is(removeAllBtn.disabled, false, "Should enable the removeAllBtn button");
}
// Counter used by addTestData to generate unique cookie names across function
// calls.
let cookieID = 0;
async function addTestData(data) {
let hosts = [];
@ -218,7 +222,10 @@ async function addTestData(data) {
}
for (let i = 0; i < (site.cookies || 0); i++) {
SiteDataTestUtils.addToCookies(site.origin, Cu.now());
SiteDataTestUtils.addToCookies({
origin: site.origin,
name: `cookie${cookieID++}`,
});
}
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(

Просмотреть файл

@ -33,10 +33,22 @@ add_task(function setup() {
});
add_task(async function testGetSites() {
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1");
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo1",
value: "bar1",
});
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo2",
value: "bar2",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096);
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN_2,
name: "foo",
value: "bar",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048);
await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2);
@ -125,10 +137,22 @@ add_task(async function testRemove() {
let uri = Services.io.newURI(EXAMPLE_ORIGIN);
PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1");
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo1",
value: "bar1",
});
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo2",
value: "bar2",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096);
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN_2,
name: "foo",
value: "bar",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048);
await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2);
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_3, 2048);
@ -182,10 +206,22 @@ add_task(async function testRemoveSiteData() {
let uri = Services.io.newURI(EXAMPLE_ORIGIN);
PermissionTestUtils.add(uri, "camera", Services.perms.ALLOW_ACTION);
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo1", "bar1");
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN, "foo2", "bar2");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo1",
value: "bar1",
});
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN,
name: "foo2",
value: "bar2",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN, 4096);
SiteDataTestUtils.addToCookies(EXAMPLE_ORIGIN_2, "foo", "bar");
SiteDataTestUtils.addToCookies({
origin: EXAMPLE_ORIGIN_2,
name: "foo",
value: "bar",
});
await SiteDataTestUtils.addToIndexedDB(EXAMPLE_ORIGIN_2, 2048);
await SiteDataTestUtils.persist(EXAMPLE_ORIGIN_2);

Просмотреть файл

@ -216,7 +216,7 @@ function setStorageEntry(storageType, originNoSuffix, firstParty, key, value) {
let origin = getOrigin(originNoSuffix, firstParty);
if (storageType == "cookie") {
SiteDataTestUtils.addToCookies(origin, key, value);
SiteDataTestUtils.addToCookies({ origin, name: key, value });
return;
}
// localStorage

Просмотреть файл

@ -46,7 +46,7 @@ async function setupTest(aCookieBehavior) {
add_task(async function testNotPurging() {
await UrlClassifierTestUtils.addTestTrackers();
setupTest(Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN);
SiteDataTestUtils.addToCookies(TRACKING_PAGE);
SiteDataTestUtils.addToCookies({ origin: TRACKING_PAGE });
Services.prefs.setIntPref(
"network.cookie.cookieBehavior",
@ -90,7 +90,7 @@ async function testIndexedDBAndLocalStorage() {
Services.perms.ALLOW_ACTION
);
SiteDataTestUtils.addToCookies(BENIGN_PAGE);
SiteDataTestUtils.addToCookies({ origin: BENIGN_PAGE });
for (let url of [
TRACKING_PAGE,
TRACKING_PAGE2,
@ -99,7 +99,7 @@ async function testIndexedDBAndLocalStorage() {
FOREIGN_PAGE3,
]) {
SiteDataTestUtils.addToLocalStorage(url);
SiteDataTestUtils.addToCookies(url);
SiteDataTestUtils.addToCookies({ origin: url });
await SiteDataTestUtils.addToIndexedDB(url);
}
@ -193,11 +193,11 @@ async function testBaseDomain() {
);
for (let origin of associatedOrigins) {
SiteDataTestUtils.addToCookies(origin);
SiteDataTestUtils.addToCookies({ origin });
}
// Add another tracker to verify we're actually purging.
SiteDataTestUtils.addToCookies(TRACKING_PAGE);
SiteDataTestUtils.addToCookies({ origin: TRACKING_PAGE });
await PurgeTrackerService.purgeTrackingCookieJars();
@ -247,10 +247,12 @@ async function testUserInteraction(ownerPage) {
Services.perms.ALLOW_ACTION
);
SiteDataTestUtils.addToCookies(RESOURCE_PAGE);
SiteDataTestUtils.addToCookies({ origin: RESOURCE_PAGE });
// Add another tracker to verify we're actually purging.
SiteDataTestUtils.addToCookies("https://another-tracking.example.net");
SiteDataTestUtils.addToCookies({
origin: "https://another-tracking.example.net",
});
await PurgeTrackerService.purgeTrackingCookieJars();
@ -430,7 +432,7 @@ async function testExpiredInteractionPermission() {
FOREIGN_PAGE3,
]) {
SiteDataTestUtils.addToLocalStorage(url);
SiteDataTestUtils.addToCookies(url);
SiteDataTestUtils.addToCookies({ origin: url });
await SiteDataTestUtils.addToIndexedDB(url);
}

Просмотреть файл

@ -60,8 +60,8 @@ add_task(async function() {
);
SiteDataTestUtils.addToLocalStorage(TRACKING_PAGE);
SiteDataTestUtils.addToCookies(BENIGN_PAGE);
SiteDataTestUtils.addToCookies(TRACKING_PAGE);
SiteDataTestUtils.addToCookies({ origin: BENIGN_PAGE });
SiteDataTestUtils.addToCookies({ origin: TRACKING_PAGE });
await SiteDataTestUtils.addToIndexedDB(TRACKING_PAGE);
let purgedHistogram = TelemetryTestUtils.getAndClearHistogram(
@ -152,8 +152,8 @@ add_task(async function() {
// Enforce deleting the same origin twice by adding two cookies and setting
// the max number of cookies per batch to 1.
SiteDataTestUtils.addToCookies(TRACKING_PAGE, "cookie1");
SiteDataTestUtils.addToCookies(TRACKING_PAGE, "cookie2");
SiteDataTestUtils.addToCookies({ origin: TRACKING_PAGE, name: "cookie1" });
SiteDataTestUtils.addToCookies({ origin: TRACKING_PAGE, name: "cookie2" });
Services.prefs.setIntPref("privacy.purge_trackers.max_purge_count", 1);
let purgedHistogram = TelemetryTestUtils.getAndClearHistogram(

Просмотреть файл

@ -31,6 +31,53 @@ XPCOMUtils.defineLazyServiceGetter(
"@mozilla.org/tracking-db-service;1",
"nsITrackingDBService"
);
XPCOMUtils.defineLazyPreferenceGetter(
this,
"gFirstPartyIsolateUseSite",
"privacy.firstparty.isolate.use_site",
false
);
function getBaseDomainFromPartitionKey(partitionKey) {
if (!partitionKey?.length) {
return undefined;
}
if (gFirstPartyIsolateUseSite) {
return partitionKey;
}
let entries = partitionKey.substr(1, partitionKey.length - 2).split(",");
if (entries.length < 2) {
return undefined;
}
return entries[1];
}
/**
* Test if host and OriginAttributes belong to a baseDomain. Also considers
* partitioned storage by inspecting OriginAttributes partitionKey.
* @param options
* @param {string} options.host - Host to compare to base domain.
* @param {object} [options.originAttributes] - Optional origin attributes to
* inspect for aBaseDomain. If omitted, partitionKey will not be matched.
* @param {string} aBaseDomain - Domain to check for. Must be a valid, non-empty
* baseDomain string.
* @returns {boolean} Whether the host or originAttributes match the base
* domain.
*/
function hasBaseDomain({ host, originAttributes = null }, aBaseDomain) {
if (Services.eTLD.hasRootDomain(host, aBaseDomain)) {
return true;
}
if (!originAttributes) {
return false;
}
let partitionKeyBaseDomain = getBaseDomainFromPartitionKey(
originAttributes.partitionKey
);
return partitionKeyBaseDomain && partitionKeyBaseDomain == aBaseDomain;
}
// Here is a list of methods cleaners may implement. These methods must return a
// Promise object.
@ -82,9 +129,17 @@ const CookieCleaner = {
return this.deleteByHost(aPrincipal.host, aPrincipal.originAttributes);
},
deleteByBaseDomain(aBaseDomain) {
// TODO: Bug 1705029
return this.deleteByHost(aBaseDomain, {});
async deleteByBaseDomain(aDomain) {
Services.cookies.cookies
.filter(({ rawHost, originAttributes }) =>
hasBaseDomain({ host: rawHost, originAttributes }, aDomain)
)
.forEach(cookie => {
Services.cookies.removeCookiesFromExactHost(
cookie.rawHost,
JSON.stringify(cookie.originAttributes)
);
});
},
deleteByRange(aFrom, aTo) {

Просмотреть файл

@ -79,27 +79,45 @@ var SiteDataTestUtils = {
},
/**
* Adds a new cookie for the specified origin, with the specified contents.
* The cookie will be valid for one day.
*
* @param {String} origin - the origin of the site to add test data for
* @param {String} name [optional] - the cookie name
* @param {String} value [optional] - the cookie value
* Adds a new cookie for the specified origin or host + path + oa, with the
* specified contents. The cookie will be valid for one day.
* @param {object} options
* @param {String} [options.origin] - Origin of the site to add test data for.
* If set, overrides host, path and originAttributes args.
* @param {String} [options.host] - Host of the site to add test data for.
* @param {String} [options.path] - Path to set cookie for.
* @param {Object} [options.originAttributes] - Object of origin attributes to
* set cookie for.
* @param {String} [options.name] - Cookie name
* @param {String} [options.value] - Cookie value
*/
addToCookies(origin, name = "foo", value = "bar") {
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
origin
);
addToCookies({
origin,
host,
path = "path",
originAttributes = {},
name = "foo",
value = "bar",
}) {
if (origin) {
let principal = Services.scriptSecurityManager.createContentPrincipalFromOrigin(
origin
);
host = principal.host;
path = principal.URI.pathQueryRef;
originAttributes = principal.originAttributes;
}
Services.cookies.add(
principal.host,
principal.URI.pathQueryRef,
host,
path,
name,
value,
false,
false,
false,
Date.now() + 24000 * 60 * 60,
principal.originAttributes,
Math.floor(Date.now() / 1000) + 24 * 60 * 60,
originAttributes,
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_UNSET
);

Просмотреть файл

@ -170,3 +170,234 @@ add_task(async function test_localfile_cookies() {
});
Assert.equal(Services.cookies.countCookiesFromHost(""), 0);
});
// The following tests ensure we properly clear (partitioned/unpartitioned)
// cookies when using deleteDataFromBaseDomain and deleteDataFromHost.
function getTestCookieName(host, topLevelBaseDomain) {
if (!topLevelBaseDomain) {
return host;
}
return `${host}_${topLevelBaseDomain}`;
}
function getTestOriginAttributes(topLevelBaseDomain, originAttributes = {}) {
if (!topLevelBaseDomain) {
return originAttributes;
}
return {
...originAttributes,
partitionKey: `(https,${topLevelBaseDomain})`,
};
}
function setTestCookie({
host,
topLevelBaseDomain = null,
originAttributes = {},
}) {
SiteDataTestUtils.addToCookies({
host,
name: getTestCookieName(host, topLevelBaseDomain),
originAttributes: getTestOriginAttributes(
topLevelBaseDomain,
originAttributes
),
});
}
function setTestCookies() {
// First party cookies
setTestCookie({ host: "example.net" });
setTestCookie({ host: "test.example.net" });
setTestCookie({ host: "example.org" });
// Third-party partitioned cookies.
setTestCookie({ host: "example.com", topLevelBaseDomain: "example.net" });
setTestCookie({
host: "example.com",
topLevelBaseDomain: "example.net",
originAttributes: { userContextId: 1 },
});
setTestCookie({ host: "example.net", topLevelBaseDomain: "example.org" });
setTestCookie({
host: "test.example.net",
topLevelBaseDomain: "example.org",
});
// Ensure we have the correct cookie test state.
// Not using countCookiesFromHost because it doesn't see partitioned cookies.
testCookieExists({ host: "example.net" });
testCookieExists({ host: "test.example.net" });
testCookieExists({ host: "example.org" });
testCookieExists({ host: "example.com", topLevelBaseDomain: "example.net" });
testCookieExists({
host: "example.com",
topLevelBaseDomain: "example.net",
originAttributes: { userContextId: 1 },
});
testCookieExists({ host: "example.net", topLevelBaseDomain: "example.org" });
testCookieExists({
host: "test.example.net",
topLevelBaseDomain: "example.org",
});
}
function testCookieExists({
host,
topLevelBaseDomain = null,
expected = true,
originAttributes = {},
}) {
let exists = Services.cookies.cookieExists(
host,
"path",
getTestCookieName(host, topLevelBaseDomain),
getTestOriginAttributes(topLevelBaseDomain, originAttributes)
);
let message = `Cookie ${expected ? "is set" : "is not set"} for ${host}`;
if (topLevelBaseDomain) {
message += ` partitioned under ${topLevelBaseDomain}`;
}
Assert.equal(exists, expected, message);
return exists;
}
/**
* Tests deleting (partitioned) cookies by base domain.
*/
add_task(async function test_baseDomain_cookies() {
Services.cookies.removeAll();
setTestCookies();
// Clear cookies of example.net including partitions.
await new Promise(aResolve => {
Services.clearData.deleteDataFromBaseDomain(
"example.net",
false,
Ci.nsIClearDataService.CLEAR_COOKIES,
aResolve
);
});
testCookieExists({ host: "example.net", expected: false });
testCookieExists({ host: "test.example.net", expected: false });
testCookieExists({ host: "example.org" });
testCookieExists({
host: "example.com",
topLevelBaseDomain: "example.net",
expected: false,
});
testCookieExists({
host: "example.com",
topLevelBaseDomain: "example.net",
originAttributes: { userContextId: 1 },
expected: false,
});
testCookieExists({
host: "example.net",
topLevelBaseDomain: "example.org",
expected: false,
});
testCookieExists({
host: "test.example.net",
topLevelBaseDomain: "example.org",
expected: false,
});
// Cleanup
Services.cookies.removeAll();
});
/**
* Tests deleting (non-partitioned) cookies by host.
*/
add_task(async function test_host_cookies() {
Services.cookies.removeAll();
setTestCookies();
// Clear cookies of example.net without partitions.
await new Promise(aResolve => {
Services.clearData.deleteDataFromHost(
"example.net",
false,
Ci.nsIClearDataService.CLEAR_COOKIES,
aResolve
);
});
testCookieExists({ host: "example.net", expected: false });
testCookieExists({ host: "test.example.net" });
testCookieExists({ host: "example.org" });
// Third-party partitioned cookies under example.net should not be cleared.
testCookieExists({ host: "example.com", topLevelBaseDomain: "example.net" });
setTestCookie({
host: "example.com",
topLevelBaseDomain: "example.net",
originAttributes: { userContextId: 1 },
});
// Third-party partitioned cookies of example.net should be removed, because
// CookieCleaner matches with host, but any partition key (oa = {}) via
// removeCookiesFromExactHost.
testCookieExists({
host: "example.net",
topLevelBaseDomain: "example.org",
expected: false,
});
testCookieExists({
host: "test.example.net",
topLevelBaseDomain: "example.org",
});
// Cleanup
Services.cookies.removeAll();
});
/**
* Tests that we correctly clear data when given a subdomain.
*/
add_task(async function test_baseDomain_cookies_subdomain() {
Services.cookies.removeAll();
setTestCookies();
// Clear cookies of test.example.net including partitions.
await new Promise(aResolve => {
Services.clearData.deleteDataFromBaseDomain(
"test.example.net",
false,
Ci.nsIClearDataService.CLEAR_COOKIES,
aResolve
);
});
testCookieExists({ host: "example.net", expected: false });
testCookieExists({ host: "test.example.net", expected: false });
testCookieExists({ host: "example.org" });
testCookieExists({
host: "example.com",
topLevelBaseDomain: "example.net",
expected: false,
});
setTestCookie({
host: "example.com",
topLevelBaseDomain: "example.net",
originAttributes: { userContextId: 1 },
expected: false,
});
testCookieExists({
host: "example.net",
topLevelBaseDomain: "example.org",
expected: false,
});
testCookieExists({
host: "test.example.net",
topLevelBaseDomain: "example.org",
expected: false,
});
// Cleanup
Services.cookies.removeAll();
});

Просмотреть файл

@ -26,7 +26,7 @@ add_task(async function test_singleDomain() {
// Let's clean up all the data.
await SiteDataTestUtils.clear();
SiteDataTestUtils.addToCookies("https://example.com");
SiteDataTestUtils.addToCookies({ origin: "https://example.com" });
// Cleaning up.
await ForgetAboutSite.removeDataFromDomain("example.com");
@ -44,12 +44,12 @@ add_task(async function test_subDomain() {
// Let's clean up all the data.
await SiteDataTestUtils.clear();
SiteDataTestUtils.addToCookies("https://example.com");
SiteDataTestUtils.addToCookies("https://sub.example.com");
SiteDataTestUtils.addToCookies("https://sub2.example.com");
SiteDataTestUtils.addToCookies("https://sub2.example.com");
SiteDataTestUtils.addToCookies({ origin: "https://example.com" });
SiteDataTestUtils.addToCookies({ origin: "https://sub.example.com" });
SiteDataTestUtils.addToCookies({ origin: "https://sub2.example.com" });
SiteDataTestUtils.addToCookies({ origin: "https://sub2.example.com" });
SiteDataTestUtils.addToCookies("https://example.org");
SiteDataTestUtils.addToCookies({ origin: "https://example.org" });
// Cleaning up.
await ForgetAboutSite.removeDataFromDomain("sub.example.com");