summaryrefslogtreecommitdiffstats
path: root/toolkit/components/cleardata/tests/unit
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /toolkit/components/cleardata/tests/unit
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/cleardata/tests/unit')
-rw-r--r--toolkit/components/cleardata/tests/unit/head.js27
-rw-r--r--toolkit/components/cleardata/tests/unit/test_basic.js19
-rw-r--r--toolkit/components/cleardata/tests/unit/test_bounce_tracking_protection.js625
-rw-r--r--toolkit/components/cleardata/tests/unit/test_certs.js233
-rw-r--r--toolkit/components/cleardata/tests/unit/test_cookie_banner_handling.js328
-rw-r--r--toolkit/components/cleardata/tests/unit/test_cookies.js393
-rw-r--r--toolkit/components/cleardata/tests/unit/test_downloads.js310
-rw-r--r--toolkit/components/cleardata/tests/unit/test_fingerprinting_protection_state.js161
-rw-r--r--toolkit/components/cleardata/tests/unit/test_identity_credential_storage.js121
-rw-r--r--toolkit/components/cleardata/tests/unit/test_network_cache.js316
-rw-r--r--toolkit/components/cleardata/tests/unit/test_passwords.js89
-rw-r--r--toolkit/components/cleardata/tests/unit/test_permissions.js471
-rw-r--r--toolkit/components/cleardata/tests/unit/test_quota.js537
-rw-r--r--toolkit/components/cleardata/tests/unit/test_security_settings.js279
-rw-r--r--toolkit/components/cleardata/tests/unit/test_storage_permission.js398
-rw-r--r--toolkit/components/cleardata/tests/unit/xpcshell.toml40
16 files changed, 4347 insertions, 0 deletions
diff --git a/toolkit/components/cleardata/tests/unit/head.js b/toolkit/components/cleardata/tests/unit/head.js
new file mode 100644
index 0000000000..5e73b8a789
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/head.js
@@ -0,0 +1,27 @@
+"use strict";
+
+const { SiteDataTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/SiteDataTestUtils.sys.mjs"
+);
+const { PermissionTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PermissionTestUtils.sys.mjs"
+);
+
+function run_test() {
+ do_get_profile();
+ run_next_test();
+}
+
+function getOAWithPartitionKey(
+ { scheme = "https", topLevelBaseDomain, port = null } = {},
+ originAttributes = {}
+) {
+ if (!topLevelBaseDomain || !scheme) {
+ return originAttributes;
+ }
+
+ return {
+ ...originAttributes,
+ partitionKey: `(${scheme},${topLevelBaseDomain}${port ? `,${port}` : ""})`,
+ };
+}
diff --git a/toolkit/components/cleardata/tests/unit/test_basic.js b/toolkit/components/cleardata/tests/unit/test_basic.js
new file mode 100644
index 0000000000..3634483ee4
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_basic.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Basic test for nsIClearDataService module.
+ */
+
+"use strict";
+
+add_task(async function test_basic() {
+ Assert.ok(!!Services.clearData);
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => {
+ Assert.equal(value, 0);
+ aResolve();
+ });
+ });
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_bounce_tracking_protection.js b/toolkit/components/cleardata/tests/unit/test_bounce_tracking_protection.js
new file mode 100644
index 0000000000..ac0eb40fd9
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_bounce_tracking_protection.js
@@ -0,0 +1,625 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "bounceTrackingProtection",
+ "@mozilla.org/bounce-tracking-protection;1",
+ "nsIBounceTrackingProtection"
+);
+
+const { CLEAR_BOUNCE_TRACKING_PROTECTION_STATE } = Ci.nsIClearDataService;
+
+const OA_DEFAULT = {};
+const OA_PRIVATE_BROWSING = { privateBrowsingId: 1 };
+const OA_CONTAINER = { userContextId: 1 };
+
+function addTestData() {
+ info("Adding test data.");
+ // Add test data for OriginAttributes {} => normal browsing with no container.
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_DEFAULT,
+ "common-bounce-tracker.com",
+ 100
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_DEFAULT,
+ "bounce-tracker-normal-browsing.com",
+ 200
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_DEFAULT,
+ "bounce-tracker-normal-browsing2.com",
+ 300
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_DEFAULT,
+ "common-user-activation.com",
+ 400
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_DEFAULT,
+ "user-activation-normal-browsing.com",
+ 500
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_DEFAULT,
+ "user-activation-normal-browsing2.com",
+ 600
+ );
+
+ // Add test data for private browsing.
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_PRIVATE_BROWSING,
+ "common-bounce-tracker.com",
+ 700
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_PRIVATE_BROWSING,
+ "bounce-tracker-private-browsing.com",
+ 800
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_PRIVATE_BROWSING,
+ "bounce-tracker-private-browsing2.com",
+ 900
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_PRIVATE_BROWSING,
+ "common-user-activation.com",
+ 1000
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_PRIVATE_BROWSING,
+ "user-activation-private-browsing.com",
+ 1100
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_PRIVATE_BROWSING,
+ "user-activation-private-browsing2.com",
+ 1200
+ );
+
+ // Add test data for a container.
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_CONTAINER,
+ "common-bounce-tracker.com",
+ 1300
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_CONTAINER,
+ "bounce-tracker-container.com",
+ 1400
+ );
+ bounceTrackingProtection.testAddBounceTrackerCandidate(
+ OA_CONTAINER,
+ "bounce-tracker-container2.com",
+ 1500
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_CONTAINER,
+ "common-user-activation.com",
+ 1600
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_CONTAINER,
+ "user-activation-container.com",
+ 1700
+ );
+ bounceTrackingProtection.testAddUserActivation(
+ OA_CONTAINER,
+ "user-activation-container2.com",
+ 1800
+ );
+}
+
+async function runDeleteBySiteHostTest(clearDataServiceFn) {
+ addTestData();
+
+ let baseDomain = "common-bounce-tracker.com";
+ info("Deleting by base domain " + baseDomain);
+ await new Promise(function (resolve) {
+ clearDataServiceFn(
+ baseDomain,
+ true,
+ CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .sort(),
+ [
+ "bounce-tracker-normal-browsing.com",
+ "bounce-tracker-normal-browsing2.com",
+ ],
+ "Should have deleted only 'common-bounce-tracker.com' for default OA."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-normal-browsing.com",
+ "user-activation-normal-browsing2.com",
+ ],
+ "Should not have deleted any user activations for default OA."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "bounce-tracker-private-browsing.com",
+ "bounce-tracker-private-browsing2.com",
+ ],
+ "Should have deleted only 'common-bounce-tracker.com' for private browsing."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-private-browsing.com",
+ "user-activation-private-browsing2.com",
+ ],
+ "Should not have deleted any user activations for private browsing."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .sort(),
+ ["bounce-tracker-container.com", "bounce-tracker-container2.com"],
+ "Should have deleted only 'common-bounce-tracker.com' for container."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-container.com",
+ "user-activation-container2.com",
+ ],
+ "Should not have deleted any user activations for container."
+ );
+
+ // Cleanup.
+ bounceTrackingProtection.clearAll();
+}
+
+do_get_profile();
+
+add_task(async function test_deleteAll() {
+ addTestData();
+
+ info("Deleting all data.");
+ await new Promise(function (resolve) {
+ Services.clearData.deleteData(
+ CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .length,
+ 0,
+ "All bounce tracker candidates for default OA should be deleted."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).length,
+ 0,
+ "All user activations for default OA should be deleted."
+ );
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
+ OA_PRIVATE_BROWSING
+ ).length,
+ 0,
+ "All bounce tracker candidates for private browsing should be deleted."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .length,
+ 0,
+ "All user activations for private browsing should be deleted."
+ );
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .length,
+ 0,
+ "All bounce tracker candidates for container 1 should be deleted."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).length,
+ 0,
+ "All user activations for container 1 should be deleted."
+ );
+});
+
+add_task(async function test_deleteByPrincipal() {
+ addTestData();
+
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("https://common-bounce-tracker.com"),
+ {}
+ );
+ console.debug("principal", principal.origin);
+
+ info("Deleting by principal " + principal.origin);
+ await new Promise(function (resolve) {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ false,
+ CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .sort(),
+ [
+ "bounce-tracker-normal-browsing.com",
+ "bounce-tracker-normal-browsing2.com",
+ ],
+ "Should have deleted only 'common-bounce-tracker.com' for default OA."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-normal-browsing.com",
+ "user-activation-normal-browsing2.com",
+ ],
+ "Should not have deleted any user activations for default OA."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "bounce-tracker-private-browsing.com",
+ "bounce-tracker-private-browsing2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted 'common-bounce-tracker.com' for private browsing."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-private-browsing.com",
+ "user-activation-private-browsing2.com",
+ ],
+ "Should not have deleted any user activations for private browsing."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .sort(),
+ [
+ "bounce-tracker-container.com",
+ "bounce-tracker-container2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted 'common-bounce-tracker.com' for container."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-container.com",
+ "user-activation-container2.com",
+ ],
+ "Should not have deleted any user activations for container."
+ );
+
+ let principal2 = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("https://common-user-activation.com"),
+ OA_CONTAINER
+ );
+
+ info("Deleting by principal " + principal2.origin);
+ await new Promise(function (resolve) {
+ Services.clearData.deleteDataFromPrincipal(
+ principal2,
+ false,
+ CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .sort(),
+ [
+ "bounce-tracker-normal-browsing.com",
+ "bounce-tracker-normal-browsing2.com",
+ ],
+ "Should not have deleted any bounce tracker candidates for default OA."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-normal-browsing.com",
+ "user-activation-normal-browsing2.com",
+ ],
+ "Should not have deleted 'common-user-activation.com' for default OA."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "bounce-tracker-private-browsing.com",
+ "bounce-tracker-private-browsing2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted any bounce tracker candidates for private browsing."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-private-browsing.com",
+ "user-activation-private-browsing2.com",
+ ],
+ "Should not have deleted 'common-user-activation.com' for private browsing."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .sort(),
+ [
+ "bounce-tracker-container.com",
+ "bounce-tracker-container2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted any bounce tracker candidates for container."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
+ ["user-activation-container.com", "user-activation-container2.com"],
+ "Should have deleted 'common-user-activation.com' for private browsing.."
+ );
+
+ // Cleanup.
+ bounceTrackingProtection.clearAll();
+});
+
+add_task(async function test_deleteByBaseDomain() {
+ await runDeleteBySiteHostTest(Services.clearData.deleteDataFromBaseDomain);
+});
+
+add_task(async function test_deleteByRange() {
+ addTestData();
+
+ let startTime = 200;
+ let endTime = 1300;
+
+ info(`Deleting by range ${startTime} - ${endTime}`);
+ await new Promise(function (resolve) {
+ Services.clearData.deleteDataInTimeRange(
+ startTime,
+ endTime,
+ true,
+ CLEAR_BOUNCE_TRACKING_PROTECTION_STATE,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .sort(),
+ ["common-bounce-tracker.com"],
+ "Should have only kept 'common-bounce-tracker.com' for default OA."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
+ [],
+ "Should not have kept any user activations for default OA."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [],
+ "Should not have kept any bounces for private browsing."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [],
+ "Should not have kept any user activations for private browsing."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .sort(),
+ ["bounce-tracker-container.com", "bounce-tracker-container2.com"],
+ "Should have only kept some bouncer trackers for container."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-container.com",
+ "user-activation-container2.com",
+ ],
+ "Should have kept all user activations for container."
+ );
+
+ // Cleanup.
+ bounceTrackingProtection.clearAll();
+});
+
+add_task(async function test_deleteByHost() {
+ await runDeleteBySiteHostTest(Services.clearData.deleteDataFromHost);
+});
+
+add_task(async function test_deleteByOriginAttributes() {
+ addTestData();
+
+ info("Deleting by origin attributes. " + JSON.stringify(OA_CONTAINER));
+ await new Promise(function (resolve) {
+ Services.clearData.deleteDataFromOriginAttributesPattern(
+ OA_CONTAINER,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .sort(),
+ [
+ "bounce-tracker-normal-browsing.com",
+ "bounce-tracker-normal-browsing2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted any bounce tracker candidates for default OA."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-normal-browsing.com",
+ "user-activation-normal-browsing2.com",
+ ],
+ "Should not have deleted any user activations for default OA."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "bounce-tracker-private-browsing.com",
+ "bounce-tracker-private-browsing2.com",
+ "common-bounce-tracker.com",
+ ],
+ "Should not have deleted any bounce tracker candidates for private browsing."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .sort(),
+ [
+ "common-user-activation.com",
+ "user-activation-private-browsing.com",
+ "user-activation-private-browsing2.com",
+ ],
+ "Should not have deleted any user activations for private browsing."
+ );
+
+ Assert.deepEqual(
+ bounceTrackingProtection
+ .testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .sort(),
+ [],
+ "Should have deleted all bounce tracker candidates for container."
+ );
+ Assert.deepEqual(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).sort(),
+ [],
+ "Should have deleted all user activations for container."
+ );
+
+ info("Deleting by origin attributes {} (all).");
+ await new Promise(function (resolve) {
+ Services.clearData.deleteDataFromOriginAttributesPattern(
+ OA_DEFAULT,
+ failedFlags => {
+ Assert.equal(failedFlags, 0, "Clearing should have succeeded");
+ resolve();
+ }
+ );
+ });
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_DEFAULT)
+ .length,
+ 0,
+ "Should have deleted all bounce tracker candidates for default OA."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_DEFAULT).length,
+ 0,
+ "Should have deleted all user activations for default OA."
+ );
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(
+ OA_PRIVATE_BROWSING
+ ).length,
+ 0,
+ "Should have deleted all bounce tracker candidates for private browsing."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_PRIVATE_BROWSING)
+ .length,
+ 0,
+ "Should have deleted all user activations for private browsing."
+ );
+
+ Assert.equal(
+ bounceTrackingProtection.testGetBounceTrackerCandidateHosts(OA_CONTAINER)
+ .length,
+ 0,
+ "Should have deleted all bounce tracker candidates for container."
+ );
+ Assert.equal(
+ bounceTrackingProtection.testGetUserActivationHosts(OA_CONTAINER).length,
+ 0,
+ "Should have deleted all user activations for container."
+ );
+
+ // Cleanup.
+ bounceTrackingProtection.clearAll();
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_certs.js b/toolkit/components/cleardata/tests/unit/test_certs.js
new file mode 100644
index 0000000000..3ff538d5a8
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_certs.js
@@ -0,0 +1,233 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const overrideService = Cc["@mozilla.org/security/certoverride;1"].getService(
+ Ci.nsICertOverrideService
+);
+const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+);
+
+const CERT_TEST =
+ "MIHhMIGcAgEAMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMTEwMzIzMjMyNTE3WhcNMTEwNDIyMjMyNTE3WjAMMQowCAYDVQQDEwFBMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxANFm7ZCfYNJViaDWTFuMClX3+9u18VFGiyLfM6xJrxir4QVtQC7VUC/WUGoBUs9COQIDAQABMA0GCSqGSIb3DQEBBQUAAzEAx2+gIwmuYjJO5SyabqIm4lB1MandHH1HQc0y0tUFshBOMESTzQRPSVwPn77a6R9t";
+
+add_task(async function () {
+ Assert.ok(Services.clearData);
+
+ const TEST_URI = Services.io.newURI("http://test.com/");
+ const ANOTHER_TEST_URI = Services.io.newURI("https://example.com/");
+ const YET_ANOTHER_TEST_URI = Services.io.newURI("https://example.test/");
+ let cert = certDB.constructX509FromBase64(CERT_TEST);
+ let flags = Ci.nsIClearDataService.CLEAR_CERT_EXCEPTIONS;
+
+ ok(cert, "Cert was created");
+
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ TEST_URI.asciiHost,
+ TEST_URI.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should not have override for ${TEST_URI.asciiHost}:${TEST_URI.port} yet`
+ );
+
+ overrideService.rememberValidityOverride(
+ TEST_URI.asciiHost,
+ TEST_URI.port,
+ {},
+ cert,
+ flags,
+ false
+ );
+
+ Assert.ok(
+ overrideService.hasMatchingOverride(
+ TEST_URI.asciiHost,
+ TEST_URI.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should have override for ${TEST_URI.asciiHost}:${TEST_URI.port} now`
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ TEST_URI.asciiHostPort,
+ true /* user request */,
+ flags,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ TEST_URI.asciiHost,
+ TEST_URI.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should not have override for ${TEST_URI.asciiHost}:${TEST_URI.port} now`
+ );
+
+ for (let uri of [TEST_URI, ANOTHER_TEST_URI, YET_ANOTHER_TEST_URI]) {
+ overrideService.rememberValidityOverride(
+ uri.asciiHost,
+ uri.port,
+ { privateBrowsingId: 1 },
+ cert,
+ flags,
+ false
+ );
+ Assert.ok(
+ overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ { privateBrowsingId: 1 },
+ cert,
+ {}
+ ),
+ `Should have added override for ${uri.asciiHost}:${uri.port} with private browsing ID`
+ );
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ { privateBrowsingId: 2 },
+ cert,
+ {}
+ ),
+ `Should not have added override for ${uri.asciiHost}:${uri.port} with private browsing ID 2`
+ );
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should not have added override for ${uri.asciiHost}:${uri.port}`
+ );
+ overrideService.rememberValidityOverride(
+ uri.asciiHost,
+ uri.port,
+ {},
+ cert,
+ flags,
+ false
+ );
+ Assert.ok(
+ overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should have added override for ${uri.asciiHost}:${uri.port}`
+ );
+ }
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(flags, value => {
+ Assert.equal(value, 0);
+ aResolve();
+ });
+ });
+
+ for (let uri of [TEST_URI, ANOTHER_TEST_URI, YET_ANOTHER_TEST_URI]) {
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ {},
+ cert,
+ {}
+ ),
+ `Should have removed override for ${uri.asciiHost}:${uri.port}`
+ );
+ Assert.ok(
+ !overrideService.hasMatchingOverride(
+ uri.asciiHost,
+ uri.port,
+ { privateBrowsingId: 1 },
+ cert,
+ {}
+ ),
+ `Should have removed override for ${uri.asciiHost}:${uri.port} with private browsing attribute`
+ );
+ }
+});
+
+add_task(async function test_deleteByBaseDomain() {
+ let toClear = [
+ Services.io.newURI("https://example.com"),
+ Services.io.newURI("http://example.com:8080"),
+ Services.io.newURI("http://test1.example.com"),
+ Services.io.newURI("http://foo.bar.example.com"),
+ ];
+
+ let toKeep = [
+ Services.io.newURI("https://example.org"),
+ Services.io.newURI("http://test1.example.org"),
+ Services.io.newURI("http://foo.bar.example.org"),
+ Services.io.newURI("http://example.test"),
+ ];
+
+ let all = toClear.concat(toKeep);
+
+ let cert = certDB.constructX509FromBase64(CERT_TEST);
+ ok(cert, "Cert was created");
+
+ all.forEach(({ asciiHost, port }) => {
+ Assert.ok(
+ !overrideService.hasMatchingOverride(asciiHost, port, {}, cert, {}),
+ `Should not have override for ${asciiHost}:${port} yet`
+ );
+
+ overrideService.rememberValidityOverride(asciiHost, port, {}, cert, false);
+
+ Assert.ok(
+ overrideService.hasMatchingOverride(asciiHost, port, {}, cert, {}),
+ `Should have override for ${asciiHost}:${port} now`
+ );
+ });
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_CERT_EXCEPTIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ toClear.forEach(({ asciiHost, port }) =>
+ Assert.ok(
+ !overrideService.hasMatchingOverride(asciiHost, port, {}, cert, {}),
+ `Should have cleared override for ${asciiHost}:${port}`
+ )
+ );
+
+ toKeep.forEach(({ asciiHost, port }) =>
+ Assert.ok(
+ overrideService.hasMatchingOverride(asciiHost, port, {}, cert, {}),
+ `Should have kept override for ${asciiHost}:${port}`
+ )
+ );
+
+ // Cleanup
+ overrideService.clearAllOverrides();
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_cookie_banner_handling.js b/toolkit/components/cleardata/tests/unit/test_cookie_banner_handling.js
new file mode 100644
index 0000000000..036f97e7ca
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_cookie_banner_handling.js
@@ -0,0 +1,328 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+do_get_profile();
+
+add_setup(_ => {
+ // Init cookieBannerService and pretend we opened a profile.
+ let cbs = Cc["@mozilla.org/cookie-banner-service;1"].getService(
+ Ci.nsIObserver
+ );
+ cbs.observe(null, "profile-after-change", null);
+});
+
+add_task(async function test_delete_exception() {
+ info("Enabling cookie banner service with MODE_REJECT");
+ Services.prefs.setIntPref(
+ "cookiebanners.service.mode",
+ Ci.nsICookieBannerService.MODE_REJECT
+ );
+
+ // Test nsIClearDataService.deleteDataFromHost
+ info("Adding an exception for example.com");
+ let uri = Services.io.newURI("https://example.com");
+
+ Services.cookieBanners.setDomainPref(
+ uri,
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ false
+ );
+
+ info("Verify that the exception is properly added");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ "The exception is properly set."
+ );
+
+ info("Trigger the deleteDataFromHost");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXCEPTION,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_UNSET,
+ "The exception is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteDataFromBaseDomain
+ info("Adding an exception for example.com");
+ Services.cookieBanners.setDomainPref(
+ uri,
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ false
+ );
+
+ info("Verify that the exception is properly added");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ "The exception is properly set."
+ );
+
+ info("Trigger the deleteDataFromBaseDomain");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXCEPTION,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_UNSET,
+ "The exception is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteDataFromPrincipal
+ info("Adding an exception for example.com");
+ Services.cookieBanners.setDomainPref(
+ uri,
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ false
+ );
+
+ info("Verify that the exception is properly added");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ "The exception is properly set."
+ );
+
+ info("Trigger the deleteDataFromPrincipal");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXCEPTION,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_UNSET,
+ "The exception is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteData
+ info("Adding an exception for example.com");
+ Services.cookieBanners.setDomainPref(
+ uri,
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ false
+ );
+
+ info("Verify that the exception is properly added");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_REJECT_OR_ACCEPT,
+ "The exception is properly set."
+ );
+
+ info("Trigger the deleteData");
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXCEPTION,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.equal(
+ Services.cookieBanners.getDomainPref(uri, false),
+ Ci.nsICookieBannerService.MODE_UNSET,
+ "The exception is properly cleared."
+ );
+
+ Services.prefs.clearUserPref("cookiebanners.service.mode");
+});
+
+add_task(async function test_delete_executed_record() {
+ info("Enabling cookie banner service with MODE_REJECT");
+ Services.prefs.setIntPref(
+ "cookiebanners.service.mode",
+ Ci.nsICookieBannerService.MODE_REJECT
+ );
+ Services.prefs.setIntPref(
+ "cookiebanners.bannerClicking.maxTriesPerSiteAndSession",
+ 1
+ );
+
+ // Test nsIClearDataService.deleteDataFromHost
+ info("Adding a record for example.com");
+ Services.cookieBanners.markSiteExecuted("example.com", true, false);
+
+ info("Verify that the record is properly added");
+ Assert.ok(
+ Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly set."
+ );
+
+ info("Trigger the deleteDataFromHost");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.ok(
+ !Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteDataFromBaseDomain
+ info("Adding a record for example.com");
+ Services.cookieBanners.markSiteExecuted("example.com", true, false);
+
+ info("Verify that the record is properly added");
+ Assert.ok(
+ Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly set."
+ );
+
+ info("Trigger the deleteDataFromBaseDomain");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.ok(
+ !Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteDataFromPrincipal
+ info("Adding a record for example.com");
+ Services.cookieBanners.markSiteExecuted("example.com", true, false);
+
+ info("Verify that the record is properly added");
+ Assert.ok(
+ Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly set."
+ );
+
+ info("Trigger the deleteDataFromPrincipal");
+ let uri = Services.io.newURI("https://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.ok(
+ !Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly cleared."
+ );
+
+ // Test nsIClearDataService.deleteData
+ info("Adding a record for example.com");
+ Services.cookieBanners.markSiteExecuted("example.com", true, false);
+
+ info("Verify that the record is properly added");
+ Assert.ok(
+ Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly set."
+ );
+
+ info("Trigger the deleteData");
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_COOKIE_BANNER_EXECUTED_RECORD,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ info("Verify that the exception is deleted");
+ Assert.ok(
+ !Services.cookieBanners.shouldStopBannerClickingForSite(
+ "example.com",
+ true,
+ false
+ ),
+ "The record is properly cleared."
+ );
+
+ Services.prefs.clearUserPref("cookiebanners.service.mode");
+ Services.prefs.clearUserPref(
+ "cookiebanners.bannerClicking.maxTriesPerSiteAndSession"
+ );
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_cookies.js b/toolkit/components/cleardata/tests/unit/test_cookies.js
new file mode 100644
index 0000000000..4bcb6d725a
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_cookies.js
@@ -0,0 +1,393 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests for cookies.
+ */
+
+"use strict";
+
+add_task(async function test_all_cookies() {
+ const expiry = Date.now() + 24 * 60 * 60;
+ Services.cookies.add(
+ "example.net",
+ "path",
+ "name",
+ "value",
+ true /* secure */,
+ true /* http only */,
+ false /* session */,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0);
+});
+
+add_task(async function test_range_cookies() {
+ const expiry = Date.now() + 24 * 60 * 60;
+ Services.cookies.add(
+ "example.net",
+ "path",
+ "name",
+ "value",
+ true /* secure */,
+ true /* http only */,
+ false /* session */,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
+
+ // The cookie is out of time range here.
+ let from = Date.now() + 60 * 60;
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataInTimeRange(
+ from * 1000,
+ expiry * 2000,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
+
+ // Now we delete all.
+ from = Date.now() - 60 * 60;
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataInTimeRange(
+ from * 1000,
+ expiry * 2000,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0);
+});
+
+add_task(async function test_principal_cookies() {
+ const expiry = Date.now() + 24 * 60 * 60;
+ Services.cookies.add(
+ "example.net",
+ "path",
+ "name",
+ "value",
+ true /* secure */,
+ true /* http only */,
+ false /* session */,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTPS
+ );
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
+
+ let uri = Services.io.newURI("http://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 1);
+
+ // Now we delete all.
+ uri = Services.io.newURI("http://example.net");
+ principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(Services.cookies.countCookiesFromHost("example.net"), 0);
+});
+
+add_task(async function test_localfile_cookies() {
+ const expiry = Date.now() + 24 * 60 * 60;
+ Services.cookies.add(
+ "", // local file
+ "path",
+ "name",
+ "value",
+ false /* secure */,
+ false /* http only */,
+ false /* session */,
+ expiry,
+ {},
+ Ci.nsICookie.SAMESITE_NONE,
+ Ci.nsICookie.SCHEME_HTTP
+ );
+
+ Assert.notEqual(Services.cookies.countCookiesFromHost(""), 0);
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromLocalFiles(
+ true,
+ Ci.nsIClearDataService.CLEAR_COOKIES,
+ aResolve
+ );
+ });
+ 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 setTestCookie({
+ host,
+ topLevelBaseDomain = null,
+ originAttributes = {},
+}) {
+ SiteDataTestUtils.addToCookies({
+ host,
+ name: getTestCookieName(host, topLevelBaseDomain),
+ originAttributes: getOAWithPartitionKey(
+ { 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),
+ getOAWithPartitionKey({ 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();
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_downloads.js b/toolkit/components/cleardata/tests/unit/test_downloads.js
new file mode 100644
index 0000000000..72de763ce3
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_downloads.js
@@ -0,0 +1,310 @@
+/**
+ * Tests for downloads.
+ */
+
+"use strict";
+
+const { Downloads } = ChromeUtils.importESModule(
+ "resource://gre/modules/Downloads.sys.mjs"
+);
+const { FileTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/FileTestUtils.sys.mjs"
+);
+
+const TEST_TARGET_FILE_NAME = "test-download.txt";
+let fileURL;
+let downloadList;
+
+function createFileURL() {
+ if (!fileURL) {
+ const file = Services.dirsvc.get("TmpD", Ci.nsIFile);
+ file.append("foo.txt");
+ file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
+
+ fileURL = Services.io.newFileURI(file);
+ }
+
+ return fileURL;
+}
+
+async function createDownloadList() {
+ if (!downloadList) {
+ Downloads._promiseListsInitialized = null;
+ Downloads._lists = {};
+ Downloads._summaries = {};
+
+ downloadList = await Downloads.getList(Downloads.ALL);
+ }
+
+ return downloadList;
+}
+
+add_task(async function test_all_downloads() {
+ const url = createFileURL();
+ const list = await createDownloadList();
+
+ // First download.
+ let download = await Downloads.createDownload({
+ source: { url: url.spec, isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ let view;
+ let removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ let items = await list.getAll();
+ Assert.equal(items.length, 1);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 0);
+});
+
+add_task(async function test_range_downloads() {
+ const url = createFileURL();
+ const list = await createDownloadList();
+
+ let download = await Downloads.createDownload({
+ source: { url: url.spec, isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ // Start + cancel. I need to have a startTime value.
+ await download.start();
+ await download.cancel();
+
+ let items = await list.getAll();
+ Assert.equal(items.length, 1);
+
+ let view;
+ let removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteDataInTimeRange(
+ download.startTime.getTime() * 1000,
+ download.startTime.getTime() * 1000,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 0);
+});
+
+add_task(async function test_principal_downloads() {
+ const list = await createDownloadList();
+
+ let download = await Downloads.createDownload({
+ source: { url: "http://example.net", isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ download = await Downloads.createDownload({
+ source: { url: "http://example.com", isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ let items = await list.getAll();
+ Assert.equal(items.length, 2);
+
+ let view;
+ let removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ let uri = Services.io.newURI("http://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 1);
+
+ removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 0);
+});
+
+add_task(async function test_basedomain_downloads() {
+ const list = await createDownloadList();
+
+ let download = await Downloads.createDownload({
+ source: { url: "http://example.net", isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ download = await Downloads.createDownload({
+ source: { url: "http://test.example.net", isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ download = await Downloads.createDownload({
+ source: { url: "https://foo.bar.example.net", isPrivate: true },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ download = await Downloads.createDownload({
+ source: { url: "http://example.com", isPrivate: false },
+ target: { path: FileTestUtils.getTempFile(TEST_TARGET_FILE_NAME).path },
+ });
+ Assert.ok(!!download);
+ list.add(download);
+
+ let items = await list.getAll();
+ Assert.equal(items.length, 4);
+
+ let view;
+ let removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.net",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 1);
+
+ removePromise = new Promise(resolve => {
+ view = {
+ onDownloadAdded() {},
+ onDownloadChanged() {},
+ onDownloadRemoved() {
+ resolve();
+ },
+ };
+ });
+
+ await list.addView(view);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOWNLOADS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ await removePromise;
+
+ items = await list.getAll();
+ Assert.equal(items.length, 0);
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_fingerprinting_protection_state.js b/toolkit/components/cleardata/tests/unit/test_fingerprinting_protection_state.js
new file mode 100644
index 0000000000..6c50f91551
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_fingerprinting_protection_state.js
@@ -0,0 +1,161 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+do_get_profile();
+
+add_task(async function test_clear_fingerprinting_protection_state() {
+ info("Enabling fingerprinting randomization");
+ Services.prefs.setBoolPref("privacy.resistFingerprinting", true);
+
+ let uri = Services.io.newURI("https://example.com");
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ let channel = Services.io.newChannelFromURI(
+ uri,
+ null, // aLoadingNode
+ principal,
+ null, // aTriggeringPrincipal
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_DOCUMENT
+ );
+
+ // Test nsIClearDataService.deleteDataFromHost
+ let key = Services.rfp.testGenerateRandomKey(channel);
+ let keyStr = key.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
+
+ // Verify that the key remains the same without clearing.
+ key = Services.rfp.testGenerateRandomKey(channel);
+ let keyStrAgain = key
+ .map(bytes => bytes.toString(16).padStart(2, "0"))
+ .join("");
+
+ Assert.equal(
+ keyStr,
+ keyStrAgain,
+ "The fingerprinting randomization key remain the same without clearing."
+ );
+
+ info("Trigger the deleteDataFromHost");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ key = Services.rfp.testGenerateRandomKey(channel);
+ let newKeyStr = key
+ .map(bytes => bytes.toString(16).padStart(2, "0"))
+ .join("");
+
+ Assert.notEqual(
+ keyStr,
+ newKeyStr,
+ "The fingerprinting randomization key is reset properly."
+ );
+
+ // Test nsIClearDataService.deleteDataFromBaseDomain
+ keyStr = newKeyStr;
+
+ info("Trigger the deleteDataFromBaseDomain");
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.com",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ key = Services.rfp.testGenerateRandomKey(channel);
+ newKeyStr = key.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
+
+ Assert.notEqual(
+ keyStr,
+ newKeyStr,
+ "The fingerprinting randomization key is reset properly."
+ );
+
+ // Test nsIClearDataService.deleteDataFromPrincipal
+ keyStr = newKeyStr;
+
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ key = Services.rfp.testGenerateRandomKey(channel);
+ newKeyStr = key.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
+
+ Assert.notEqual(
+ keyStr,
+ newKeyStr,
+ "The fingerprinting randomization key is reset properly."
+ );
+
+ // Test nsIClearDataService.deleteData
+ keyStr = newKeyStr;
+
+ // Generate a key for another site.
+ uri = Services.io.newURI("https://example.org");
+ principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});
+ let channelAnother = Services.io.newChannelFromURI(
+ uri,
+ null, // aLoadingNode
+ principal,
+ null, // aTriggeringPrincipal
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_DOCUMENT
+ );
+ key = Services.rfp.testGenerateRandomKey(channelAnother);
+ let keyStrAnother = key
+ .map(bytes => bytes.toString(16).padStart(2, "0"))
+ .join("");
+
+ info("Trigger the deleteData");
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_FINGERPRINTING_PROTECTION_STATE,
+ _ => {
+ resolve();
+ }
+ );
+ });
+
+ key = Services.rfp.testGenerateRandomKey(channel);
+ newKeyStr = key.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
+
+ Assert.notEqual(
+ keyStr,
+ newKeyStr,
+ "The fingerprinting randomization key is reset properly."
+ );
+
+ // Verify whether deleteData clears another site as well.
+ key = Services.rfp.testGenerateRandomKey(channelAnother);
+ newKeyStr = key.map(bytes => bytes.toString(16).padStart(2, "0")).join("");
+
+ Assert.notEqual(
+ keyStrAnother,
+ newKeyStr,
+ "The fingerprinting randomization key is reset properly for another site."
+ );
+
+ Services.prefs.clearUserPref("privacy.resistFingerprinting");
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_identity_credential_storage.js b/toolkit/components/cleardata/tests/unit/test_identity_credential_storage.js
new file mode 100644
index 0000000000..13369fc787
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_identity_credential_storage.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+XPCOMUtils.defineLazyServiceGetter(
+ this,
+ "IdentityCredentialStorageService",
+ "@mozilla.org/browser/identity-credential-storage-service;1",
+ "nsIIdentityCredentialStorageService"
+);
+
+do_get_profile();
+
+add_task(async function test_deleteByRange() {
+ Services.prefs.setBoolPref(
+ "dom.security.credentialmanagement.identity.enabled",
+ true
+ );
+ const expiry = Date.now() + 24 * 60 * 60;
+ let rpPrincipal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("https://rp.com/"),
+ {}
+ );
+ let idpPrincipal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI("https://idp.com/"),
+ {}
+ );
+ const credentialID = "ID";
+
+ // Test initial value
+ let registered = {};
+ let allowLogout = {};
+ IdentityCredentialStorageService.getState(
+ rpPrincipal,
+ idpPrincipal,
+ credentialID,
+ registered,
+ allowLogout
+ );
+ Assert.ok(!registered.value, "Should not be registered initially.");
+ Assert.ok(!allowLogout.value, "Should not allow logout initially.");
+
+ // Set and read a value
+ IdentityCredentialStorageService.setState(
+ rpPrincipal,
+ idpPrincipal,
+ credentialID,
+ true,
+ true
+ );
+
+ IdentityCredentialStorageService.getState(
+ rpPrincipal,
+ idpPrincipal,
+ credentialID,
+ registered,
+ allowLogout
+ );
+ Assert.ok(registered.value, "Should be registered by set.");
+ Assert.ok(allowLogout.value, "Should now allow logout by set.");
+
+ let from = Date.now() + 60 * 60;
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataInTimeRange(
+ from * 1000,
+ expiry * 1000,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_CREDENTIAL_MANAGER_STATE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ IdentityCredentialStorageService.getState(
+ rpPrincipal,
+ idpPrincipal,
+ credentialID,
+ registered,
+ allowLogout
+ );
+
+ Assert.ok(
+ registered.value,
+ "Should be existing since the value is not deleted"
+ );
+
+ from = Date.now() - 60 * 60;
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataInTimeRange(
+ from * 1000,
+ expiry * 1000,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_CREDENTIAL_MANAGER_STATE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ IdentityCredentialStorageService.getState(
+ rpPrincipal,
+ idpPrincipal,
+ credentialID,
+ registered,
+ allowLogout
+ );
+ Assert.ok(!registered.value, "Should not be existing");
+
+ Services.prefs.clearUserPref(
+ "dom.security.credentialmanagement.identity.enabled"
+ );
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_network_cache.js b/toolkit/components/cleardata/tests/unit/test_network_cache.js
new file mode 100644
index 0000000000..bb54cdc6a8
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_network_cache.js
@@ -0,0 +1,316 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test clearing cache.
+ */
+
+"use strict";
+
+function getPartitionedLoadContextInfo(
+ { scheme, topLevelBaseDomain, port },
+ originAttributes = {}
+) {
+ return Services.loadContextInfo.custom(
+ false,
+ getOAWithPartitionKey(
+ { scheme, topLevelBaseDomain, port },
+ originAttributes
+ )
+ );
+}
+
+add_task(async function test_deleteFromHost() {
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.com",
+ true,
+ Ci.nsIClearDataService.CLEAR_NETWORK_CACHE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache is cleared"
+ );
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache is cleared"
+ );
+
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await SiteDataTestUtils.clear();
+});
+
+add_task(async function test_deleteFromPrincipal() {
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ let principal =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "http://example.com/"
+ );
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true,
+ Ci.nsIClearDataService.CLEAR_NETWORK_CACHE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache is cleared"
+ );
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache is cleared"
+ );
+
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await SiteDataTestUtils.clear();
+});
+
+add_task(async function test_deleteFromBaseDomain() {
+ for (let cacheType of ["disk", "memory"]) {
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", cacheType);
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", cacheType),
+ `The ${cacheType} cache has an entry.`
+ );
+
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", cacheType);
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", cacheType),
+ `The ${cacheType} cache has an entry.`
+ );
+
+ // Partitioned cache.
+ await SiteDataTestUtils.addCacheEntry(
+ "http://example.com/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.org" })
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry(
+ "http://example.com/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.org" })
+ ),
+ `The ${cacheType} cache has a partitioned entry`
+ );
+ await SiteDataTestUtils.addCacheEntry(
+ "http://example.org/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.com" })
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry(
+ "http://example.org/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.com" })
+ ),
+ `The ${cacheType} cache has a partitioned entry`
+ );
+
+ // Clear an unrelated base domain.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "foo.com",
+ true,
+ Ci.nsIClearDataService.CLEAR_NETWORK_CACHE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ // Should still have all cache entries.
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", cacheType),
+ `The ${cacheType} cache has an entry.`
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", cacheType),
+ `The ${cacheType} cache has an entry.`
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry(
+ "http://example.com/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.org" })
+ ),
+ `The ${cacheType} cache has a partitioned entry`
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry(
+ "http://example.org/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.com" })
+ ),
+ `The ${cacheType} cache has a partitioned entry`
+ );
+
+ // Clear data for example.com
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.com",
+ true,
+ Ci.nsIClearDataService.CLEAR_NETWORK_CACHE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", cacheType),
+ `The ${cacheType} cache is cleared.`
+ );
+
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", cacheType),
+ `The ${cacheType} cache has an entry.`
+ );
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry(
+ "http://example.com/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.org" })
+ ),
+ `The ${cacheType} cache is cleared.`
+ );
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry(
+ "http://example.org/",
+ cacheType,
+ getPartitionedLoadContextInfo({ topLevelBaseDomain: "example.com" })
+ ),
+ `The ${cacheType} cache is cleared.`
+ );
+ await SiteDataTestUtils.clear();
+ }
+});
+
+add_task(async function test_deleteAll() {
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.com/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "disk");
+ await SiteDataTestUtils.addCacheEntry("http://example.org/", "memory");
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache has an entry"
+ );
+ Assert.ok(
+ SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache has an entry"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_NETWORK_CACHE,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "disk"),
+ "The disk cache is cleared"
+ );
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.com/", "memory"),
+ "The memory cache is cleared"
+ );
+
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.org/", "disk"),
+ "The disk cache is cleared"
+ );
+ Assert.ok(
+ !SiteDataTestUtils.hasCacheEntry("http://example.org/", "memory"),
+ "The memory cache is cleared"
+ );
+
+ await SiteDataTestUtils.clear();
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_passwords.js b/toolkit/components/cleardata/tests/unit/test_passwords.js
new file mode 100644
index 0000000000..7e63bd8fa3
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_passwords.js
@@ -0,0 +1,89 @@
+/**
+ * Tests for passwords.
+ */
+
+"use strict";
+
+const URL = "http://example.com";
+
+const { LoginTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/LoginTestUtils.sys.mjs"
+);
+
+add_task(async function test_principal_downloads() {
+ // Store the strings "user" and "pass" using similarly looking glyphs.
+ let loginInfo = LoginTestUtils.testData.formLogin({
+ origin: URL,
+ formActionOrigin: URL,
+ username: "admin",
+ password: "12345678",
+ usernameField: "field_username",
+ passwordField: "field_password",
+ });
+ await Services.logins.addLoginAsync(loginInfo);
+
+ Assert.equal(await countLogins(URL), 1);
+
+ let uri = Services.io.newURI(URL);
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ await new Promise(resolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_PASSWORDS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ Assert.equal(await countLogins(URL), 0);
+
+ LoginTestUtils.clearData();
+});
+
+add_task(async function test_all() {
+ // Store the strings "user" and "pass" using similarly looking glyphs.
+ let loginInfo = LoginTestUtils.testData.formLogin({
+ origin: URL,
+ formActionOrigin: URL,
+ username: "admin",
+ password: "12345678",
+ usernameField: "field_username",
+ passwordField: "field_password",
+ });
+ await Services.logins.addLoginAsync(loginInfo);
+
+ Assert.equal(await countLogins(URL), 1);
+
+ await new Promise(resolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PASSWORDS,
+ value => {
+ Assert.equal(value, 0);
+ resolve();
+ }
+ );
+ });
+
+ Assert.equal(await countLogins(URL), 0);
+
+ LoginTestUtils.clearData();
+});
+
+async function countLogins(origin) {
+ let count = 0;
+ const logins = await Services.logins.getAllLogins();
+ for (const login of logins) {
+ if (login.origin == origin) {
+ ++count;
+ }
+ }
+
+ return count;
+}
diff --git a/toolkit/components/cleardata/tests/unit/test_permissions.js b/toolkit/components/cleardata/tests/unit/test_permissions.js
new file mode 100644
index 0000000000..1f46ab5015
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_permissions.js
@@ -0,0 +1,471 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests for permissions
+ */
+
+"use strict";
+
+add_task(async function test_all_permissions() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) != null
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) == null
+ );
+});
+
+add_task(async function test_principal_permissions() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ const anotherUri = Services.io.newURI("https://example.com");
+ const anotherPrincipal =
+ Services.scriptSecurityManager.createContentPrincipal(anotherUri, {});
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(anotherPrincipal, "cookie", true) != null
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) == null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(anotherPrincipal, "cookie", true) != null
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
+
+function addTestPermissions() {
+ Services.perms.removeAll();
+
+ PermissionTestUtils.add(
+ "https://example.net",
+ "geo",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "http://example.net",
+ "cookie",
+ Services.perms.DENY_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://bar.example.net",
+ "geo",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://foo.bar.example.net",
+ "geo",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://example.com",
+ "3rdPartyStorage^https://example.net",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://example.com",
+ "3rdPartyFrameStorage^https://example.net",
+ Services.perms.ALLOW_ACTION
+ );
+
+ PermissionTestUtils.add(
+ "https://example.com",
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "http://example.com",
+ "geo",
+ Services.perms.ALLOW_ACTION
+ );
+
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject("https://example.net", "geo", true)
+ .capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "http://example.net",
+ "cookie",
+ true
+ ).capability,
+ Services.perms.DENY_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://bar.example.net",
+ "geo",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://foo.bar.example.net",
+ "geo",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyStorage^https://example.net",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyFrameStorage^https://example.net",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "cookie",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject("http://example.com", "geo", true)
+ .capability,
+ Services.perms.ALLOW_ACTION
+ );
+}
+
+add_task(async function test_basedomain_permissions() {
+ for (let domain of [
+ "example.net",
+ "test.example.net",
+ "foo.bar.example.net",
+ ]) {
+ addTestPermissions();
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ domain,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ // Should have cleared all entries associated with the base domain.
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://example.net",
+ "geo",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "http://example.net",
+ "cookie",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://bar.example.net",
+ "geo",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://foo.bar.example.net",
+ "geo",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyStorage^https://example.net",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyFrameStorage^https://example.net",
+ true
+ )
+ );
+
+ // Unrelated entries should still exist.
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "cookie",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject("http://example.com", "geo", true)
+ .capability,
+ Services.perms.ALLOW_ACTION
+ );
+ }
+
+ Services.perms.removeAll();
+});
+
+add_task(async function test_host_permissions() {
+ addTestPermissions();
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ "bar.example.net",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ // Should have cleared all entries associated with the host and its
+ // subdomains.
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://bar.example.net",
+ "geo",
+ true
+ )
+ );
+ Assert.ok(
+ !PermissionTestUtils.getPermissionObject(
+ "https://foo.bar.example.net",
+ "geo",
+ true
+ )
+ );
+
+ // Unrelated entries should still exist.
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject("https://example.net", "geo", true)
+ .capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "http://example.net",
+ "cookie",
+ true
+ ).capability,
+ Services.perms.DENY_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyStorage^https://example.net",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "3rdPartyFrameStorage^https://example.net",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject(
+ "https://example.com",
+ "cookie",
+ true
+ ).capability,
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.getPermissionObject("http://example.com", "geo", true)
+ .capability,
+ Services.perms.ALLOW_ACTION
+ );
+
+ Services.perms.removeAll();
+});
+
+add_task(async function test_3rdpartystorage_permissions() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ Services.perms.addFromPrincipal(
+ principal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+
+ const anotherUri = Services.io.newURI("https://example.com");
+ const anotherPrincipal =
+ Services.scriptSecurityManager.createContentPrincipal(anotherUri, {});
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "3rdPartyStorage^https://example.net",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "3rdPartyFrameStorage^https://example.net",
+ Services.perms.ALLOW_ACTION
+ );
+
+ const oneMoreUri = Services.io.newURI("https://example.org");
+ const oneMorePrincipal =
+ Services.scriptSecurityManager.createContentPrincipal(oneMoreUri, {});
+ Services.perms.addFromPrincipal(
+ oneMorePrincipal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(anotherPrincipal, "cookie", true) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(
+ anotherPrincipal,
+ "3rdPartyStorage^https://example.net",
+ true
+ ) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(
+ anotherPrincipal,
+ "3rdPartyFrameStorage^https://example.net",
+ true
+ ) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(oneMorePrincipal, "cookie", true) != null
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.ok(
+ Services.perms.getPermissionObject(principal, "cookie", true) == null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(anotherPrincipal, "cookie", true) != null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(
+ anotherPrincipal,
+ "3rdPartyStorage^https://example.net",
+ true
+ ) == null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(
+ anotherPrincipal,
+ "3rdPartyFrameStorage^https://example.net",
+ true
+ ) == null
+ );
+ Assert.ok(
+ Services.perms.getPermissionObject(oneMorePrincipal, "cookie", true) != null
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_quota.js b/toolkit/components/cleardata/tests/unit/test_quota.js
new file mode 100644
index 0000000000..95c3025781
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_quota.js
@@ -0,0 +1,537 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests for the QuotaCleaner.
+ */
+
+"use strict";
+
+// The following tests ensure we properly clear (partitioned/unpartitioned)
+// localStorage and indexedDB when using deleteDataFromBaseDomain,
+// deleteDataFromHost and deleteDataFromPrincipal.
+
+// Skip localStorage tests when using legacy localStorage. The legacy
+// localStorage implementation does not support clearing data by principal. See
+// Bug 1688221, Bug 1688665.
+const skipLocalStorageTests = Services.prefs.getBoolPref(
+ "dom.storage.enable_unsupported_legacy_implementation"
+);
+
+/**
+ * Create an origin with partitionKey.
+ * @param {String} host - Host portion of origin to create.
+ * @param {String} [topLevelBaseDomain] - Optional first party base domain to use for partitionKey.
+ * @param {Object} [originAttributes] - Optional object of origin attributes to
+ * set. If topLevelBaseDomain is passed, the partitionKey will be overwritten.
+ * @returns {String} Origin with suffix.
+ */
+function getOrigin(host, topLevelBaseDomain, originAttributes = {}) {
+ return getPrincipal(host, topLevelBaseDomain, originAttributes).origin;
+}
+
+function getPrincipal(host, topLevelBaseDomain, originAttributes = {}) {
+ originAttributes = getOAWithPartitionKey(
+ { topLevelBaseDomain },
+ originAttributes
+ );
+ let principal = Services.scriptSecurityManager.createContentPrincipal(
+ Services.io.newURI(`https://${host}`),
+ originAttributes
+ );
+ return principal;
+}
+
+function getTestEntryName(host, topLevelBaseDomain) {
+ if (!topLevelBaseDomain) {
+ return host;
+ }
+ return `${host}_${topLevelBaseDomain}`;
+}
+
+function setTestEntry({
+ storageType,
+ host,
+ topLevelBaseDomain = null,
+ originAttributes = {},
+}) {
+ let origin = getOrigin(host, topLevelBaseDomain, originAttributes);
+ if (storageType == "localStorage") {
+ SiteDataTestUtils.addToLocalStorage(
+ origin,
+ getTestEntryName(host, topLevelBaseDomain),
+ "bar"
+ );
+ return;
+ }
+ SiteDataTestUtils.addToIndexedDB(origin);
+}
+
+async function testEntryExists({
+ storageType,
+ host,
+ topLevelBaseDomain = null,
+ expected = true,
+ originAttributes = {},
+}) {
+ let exists;
+ let origin = getOrigin(host, topLevelBaseDomain, originAttributes);
+ if (storageType == "localStorage") {
+ exists = SiteDataTestUtils.hasLocalStorage(origin, [
+ { key: getTestEntryName(host, topLevelBaseDomain), value: "bar" },
+ ]);
+ } else {
+ exists = await SiteDataTestUtils.hasIndexedDB(origin);
+ }
+
+ let message = `${storageType} entry ${
+ expected ? "is set" : "is not set"
+ } for ${host}`;
+ if (topLevelBaseDomain) {
+ message += ` partitioned under ${topLevelBaseDomain}`;
+ }
+ Assert.equal(exists, expected, message);
+ return exists;
+}
+
+const TEST_ORIGINS = [
+ // First party
+ { host: "example.net" },
+ { host: "test.example.net" },
+ { host: "example.org" },
+
+ // Third-party partitioned.
+ { host: "example.com", topLevelBaseDomain: "example.net" },
+ {
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ originAttributes: { userContextId: 1 },
+ },
+ { host: "example.net", topLevelBaseDomain: "example.org" },
+ { host: "test.example.net", topLevelBaseDomain: "example.org" },
+];
+
+async function setTestEntries(storageType) {
+ for (const origin of TEST_ORIGINS) {
+ setTestEntry({ storageType, ...origin });
+ }
+
+ // Ensure we have the correct storage test state.
+ for (const origin of TEST_ORIGINS) {
+ await testEntryExists({ storageType, ...origin });
+ }
+}
+
+/**
+ * Run the base domain test with either localStorage or indexedDB.
+ * @param {('localStorage'|'indexedDB')} storageType
+ */
+async function runTestBaseDomain(storageType) {
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+ await setTestEntries(storageType);
+
+ // Clear entries of example.net including partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ await testEntryExists({ storageType, host: "example.net", expected: false });
+ await testEntryExists({
+ storageType,
+ host: "test.example.net",
+ expected: false,
+ });
+ await testEntryExists({ storageType, host: "example.org" });
+
+ await testEntryExists({
+ storageType,
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ expected: false,
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ originAttributes: { userContextId: 1 },
+ expected: false,
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expected: false,
+ });
+ await testEntryExists({
+ storageType,
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expected: false,
+ });
+
+ // Cleanup
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+}
+
+/**
+ * Run the host test with either localStorage or indexedDB.
+ * @param {('localStorage'|'indexedDB')} storageType
+ */
+async function runTestHost(storageType) {
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+ await setTestEntries(storageType);
+
+ // Clear entries of example.net without partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ await testEntryExists({ storageType, host: "example.net", expected: false });
+ // QuotaCleaner#deleteByHost also clears subdomains.
+ await testEntryExists({
+ storageType,
+ host: "test.example.net",
+ expected: false,
+ });
+ await testEntryExists({ storageType, host: "example.org" });
+
+ await testEntryExists({
+ storageType,
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ expected: true,
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ originAttributes: { userContextId: 1 },
+ expected: true,
+ });
+ // QuotaCleaner#deleteByHost ignores partitionKey.
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expected: false,
+ });
+ await testEntryExists({
+ storageType,
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expected: false,
+ });
+
+ // Cleanup
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+}
+
+/**
+ * Run the principal test with either localStorage or indexedDB.
+ * @param {('localStorage'|'indexedDB')} storageType
+ */
+async function runTestPrincipal(storageType) {
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ // First party
+ setTestEntry({ storageType, host: "example.net" });
+ setTestEntry({
+ storageType,
+ host: "example.net",
+ originAttributes: { userContextId: 2 },
+ });
+ setTestEntry({
+ storageType,
+ host: "example.net",
+ originAttributes: { privateBrowsingId: 1 },
+ });
+ setTestEntry({ storageType, host: "test.example.net" });
+ setTestEntry({ storageType, host: "example.org" });
+
+ // Third-party partitioned.
+ setTestEntry({
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.com",
+ });
+
+ // Ensure we have the correct storage test state.
+ await testEntryExists({ storageType, host: "example.net" });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ originAttributes: { userContextId: 2 },
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ originAttributes: { privateBrowsingId: 1 },
+ });
+ await testEntryExists({ storageType, host: "test.example.net" });
+ await testEntryExists({ storageType, host: "example.org" });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.com",
+ });
+
+ // Clear entries from principal with custom OA.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ getPrincipal("example.net", null, { userContextId: 2 }),
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ // Test that we only deleted entries for the exact origin.
+ await testEntryExists({ storageType, host: "example.net" });
+ await testEntryExists({
+ expected: false,
+ storageType,
+ host: "example.net",
+ originAttributes: { userContextId: 2 },
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ originAttributes: { privateBrowsingId: 1 },
+ });
+ await testEntryExists({ storageType, host: "test.example.net" });
+ await testEntryExists({ storageType, host: "example.org" });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.com",
+ });
+
+ // Clear entries of from partitioned principal.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ getPrincipal("example.net", "example.com"),
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ // Test that we only deleted entries for the partition.
+ await testEntryExists({ storageType, host: "example.net" });
+ await testEntryExists({
+ expected: false,
+ storageType,
+ host: "example.net",
+ originAttributes: { userContextId: 2 },
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ originAttributes: { privateBrowsingId: 1 },
+ });
+ await testEntryExists({ storageType, host: "test.example.net" });
+ await testEntryExists({ storageType, host: "example.org" });
+ await testEntryExists({
+ expected: false,
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.com",
+ });
+
+ // Clear entries of from principal without suffix.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ getPrincipal("example.net", null),
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ // Test that we only deleted entries for the given principal, and not entries
+ // for principals with the same host, but different OriginAttributes or
+ // subdomains.
+ await testEntryExists({ expected: false, storageType, host: "example.net" });
+ await testEntryExists({
+ expected: false,
+ storageType,
+ host: "example.net",
+ originAttributes: { userContextId: 2 },
+ });
+ await testEntryExists({
+ storageType,
+ host: "example.net",
+ originAttributes: { privateBrowsingId: 1 },
+ });
+
+ await testEntryExists({ storageType, host: "test.example.net" });
+ await testEntryExists({ storageType, host: "example.org" });
+ await testEntryExists({
+ expected: false,
+ storageType,
+ host: "example.net",
+ topLevelBaseDomain: "example.com",
+ });
+
+ // Cleanup
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+}
+
+// Tests
+
+add_task(function setup() {
+ // Allow setting local storage in xpcshell tests.
+ Services.prefs.setBoolPref("dom.storage.client_validation", false);
+});
+
+/**
+ * Tests deleting localStorage entries by host.
+ */
+add_task(async function test_host_localStorage() {
+ await runTestHost("localStorage");
+});
+
+/**
+ * Tests deleting indexedDB entries by host.
+ */
+add_task(async function test_host_indexedDB() {
+ await runTestHost("indexedDB");
+});
+
+/**
+ * Tests deleting (partitioned) localStorage entries by base domain.
+ */
+add_task(async function test_baseDomain_localStorage() {
+ await runTestBaseDomain("localStorage");
+});
+
+/**
+ * Tests deleting (partitioned) indexedDB entries by base domain.
+ */
+add_task(async function test_baseDomain_indexedDB() {
+ await runTestBaseDomain("indexedDB");
+});
+
+/**
+ * Tests deleting localStorage entries by principal.
+ */
+add_task(async function test_principal_localStorage() {
+ // Bug 1688221, Bug 1688665.
+ if (skipLocalStorageTests) {
+ info("Skipping test");
+ return;
+ }
+ await runTestPrincipal("localStorage");
+});
+
+function getRelativeFile(...components) {
+ const profileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+
+ const file = profileDir.clone();
+ for (const component of components) {
+ file.append(component);
+ }
+
+ return file;
+}
+
+function countSubitems(file) {
+ const entriesIterator = file.directoryEntries;
+ let count = 0;
+ while (entriesIterator.hasMoreElements()) {
+ ++count;
+ entriesIterator.nextFile;
+ }
+ return count;
+}
+
+add_task(async function test_deleteAllAtShutdown() {
+ const storageType = "indexedDB";
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ const toBeRemovedDir = getRelativeFile("storage", "to-be-removed");
+ if (toBeRemovedDir.exists()) {
+ toBeRemovedDir.remove(true);
+ }
+
+ await setTestEntries(storageType);
+
+ Services.startup.advanceShutdownPhase(
+ Services.startup.SHUTDOWN_PHASE_APPSHUTDOWNTEARDOWN
+ );
+
+ // Clear entries from principal with custom OA.
+ for (const origin of TEST_ORIGINS) {
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ getPrincipal(
+ origin.host,
+ origin.topLevelBaseDomain,
+ origin.originAttributes
+ ),
+ false,
+ Ci.nsIClearDataService.CLEAR_DOM_QUOTA,
+ aResolve
+ );
+ });
+
+ await testEntryExists({ expected: false, storageType, ...origin });
+ }
+
+ Assert.ok(
+ toBeRemovedDir.exists(),
+ "to-be-removed directory should exist now"
+ );
+
+ Assert.equal(
+ countSubitems(toBeRemovedDir),
+ TEST_ORIGINS.length,
+ `storage/to-be-removed has ${TEST_ORIGINS.length} subdirectories`
+ );
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_security_settings.js b/toolkit/components/cleardata/tests/unit/test_security_settings.js
new file mode 100644
index 0000000000..b14f567bab
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_security_settings.js
@@ -0,0 +1,279 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test for SecuritySettingsCleaner.
+ * This tests both, the SiteSecurityService and the ClientAuthRememberService.
+ */
+
+"use strict";
+
+let gSSService = Cc["@mozilla.org/ssservice;1"].getService(
+ Ci.nsISiteSecurityService
+);
+
+let cars = Cc["@mozilla.org/security/clientAuthRememberService;1"].getService(
+ Ci.nsIClientAuthRememberService
+);
+
+let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
+ Ci.nsIX509CertDB
+);
+
+// These are not actual server and client certs. The ClientAuthRememberService
+// does not care which certs we store decisions for, as long as they're valid.
+let [clientCert] = certDB.getCerts();
+
+function addSecurityInfo({ host, topLevelBaseDomain, originAttributes = {} }) {
+ let attrs = getOAWithPartitionKey({ topLevelBaseDomain }, originAttributes);
+
+ let uri = Services.io.newURI(`https://${host}`);
+
+ gSSService.processHeader(uri, "max-age=1000;", attrs);
+
+ cars.rememberDecisionScriptable(host, attrs, clientCert);
+}
+
+function addTestSecurityInfo() {
+ // First party
+ addSecurityInfo({ host: "example.net" });
+ addSecurityInfo({ host: "test.example.net" });
+ addSecurityInfo({ host: "example.org" });
+
+ // Third-party partitioned
+ addSecurityInfo({ host: "example.com", topLevelBaseDomain: "example.net" });
+ addSecurityInfo({ host: "example.net", topLevelBaseDomain: "example.org" });
+ addSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ });
+
+ // Ensure we have the correct state initially.
+ testSecurityInfo({ host: "example.net" });
+ testSecurityInfo({ host: "test.example.net" });
+ testSecurityInfo({ host: "example.org" });
+ testSecurityInfo({ host: "example.com", topLevelBaseDomain: "example.net" });
+ testSecurityInfo({ host: "example.net", topLevelBaseDomain: "example.org" });
+ testSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ });
+}
+
+function testSecurityInfo({
+ host,
+ topLevelBaseDomain,
+ expectedHSTS = true,
+ expectedCARS = true,
+ originAttributes = {},
+}) {
+ let attrs = getOAWithPartitionKey({ topLevelBaseDomain }, originAttributes);
+
+ let messageSuffix = `for ${host}`;
+ if (topLevelBaseDomain) {
+ messageSuffix += ` partitioned under ${topLevelBaseDomain}`;
+ }
+
+ let uri = Services.io.newURI(`https://${host}`);
+ let isSecure = gSSService.isSecureURI(uri, attrs);
+ Assert.equal(
+ isSecure,
+ expectedHSTS,
+ `HSTS ${expectedHSTS ? "is set" : "is not set"} ${messageSuffix}`
+ );
+
+ let hasRemembered = cars.hasRememberedDecisionScriptable(host, attrs, {});
+ // CARS deleteDecisionsByHost does not include subdomains. That means for some
+ // test cases we expect a different remembered state.
+ Assert.equal(
+ hasRemembered,
+ expectedCARS,
+ `CAR ${expectedCARS ? "is set" : "is not set"} ${messageSuffix}`
+ );
+}
+
+add_task(async function test_baseDomain() {
+ gSSService.clearAll();
+
+ // ---- hsts cleaner ----
+ addTestSecurityInfo();
+
+ // Clear hsts data of example.net including partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_HSTS,
+ aResolve
+ );
+ });
+
+ testSecurityInfo({
+ host: "example.net",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ // HSTSCleaner also removes subdomain settings.
+ testSecurityInfo({
+ host: "test.example.net",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({ host: "example.org" });
+
+ testSecurityInfo({
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+
+ // ---- client auth remember cleaner -----
+ addTestSecurityInfo();
+
+ // Clear security settings of example.net including partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_CLIENT_AUTH_REMEMBER_SERVICE,
+ aResolve
+ );
+ });
+
+ testSecurityInfo({
+ host: "example.net",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ // ClientAuthRememberCleaner also removes subdomain settings.
+ testSecurityInfo({
+ host: "test.example.net",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ testSecurityInfo({ host: "example.org" });
+
+ testSecurityInfo({
+ host: "example.com",
+ topLevelBaseDomain: "example.net",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ testSecurityInfo({
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+
+ // Cleanup
+ gSSService.clearAll();
+});
+
+add_task(async function test_host() {
+ gSSService.clearAll();
+
+ // ---- HSTS cleaer ----
+ addTestSecurityInfo();
+
+ // Clear security settings of example.net without partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_HSTS,
+ aResolve
+ );
+ });
+
+ testSecurityInfo({
+ host: "example.net",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({ host: "example.org" });
+
+ testSecurityInfo({ host: "example.com", topLevelBaseDomain: "example.net" });
+ testSecurityInfo({
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: false,
+ expectedCARS: true,
+ });
+
+ // Cleanup
+ gSSService.clearAll();
+
+ // --- clientAuthRemember cleaner ---
+
+ addTestSecurityInfo();
+
+ // Clear security settings of example.net without partitions.
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromHost(
+ "example.net",
+ false,
+ Ci.nsIClearDataService.CLEAR_CLIENT_AUTH_REMEMBER_SERVICE,
+ aResolve
+ );
+ });
+
+ testSecurityInfo({
+ host: "example.net",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ expectedHSTS: true,
+ expectedCARS: true,
+ });
+ testSecurityInfo({ host: "example.org" });
+
+ testSecurityInfo({ host: "example.com", topLevelBaseDomain: "example.net" });
+ testSecurityInfo({
+ host: "example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: true,
+ expectedCARS: false,
+ });
+ testSecurityInfo({
+ host: "test.example.net",
+ topLevelBaseDomain: "example.org",
+ expectedHSTS: true,
+ expectedCARS: true,
+ });
+
+ // Cleanup
+ gSSService.clearAll();
+});
diff --git a/toolkit/components/cleardata/tests/unit/test_storage_permission.js b/toolkit/components/cleardata/tests/unit/test_storage_permission.js
new file mode 100644
index 0000000000..a44e9f2c6a
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/test_storage_permission.js
@@ -0,0 +1,398 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests for permissions
+ */
+
+"use strict";
+
+// Test that only the storageAccessAPI gets removed.
+add_task(async function test_removing_storage_permission() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ principal,
+ "cookie",
+ Services.perms.ALLOW_ACTION
+ );
+
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "There is a storageAccessAPI permission set"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION,
+ "the storageAccessAPI permission has been removed"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(principal, "cookie"),
+ Services.perms.ALLOW_ACTION,
+ "the cookie permission has not been removed"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
+
+// Test that the storageAccessAPI gets removed from a particular principal
+add_task(async function test_removing_storage_permission_from_principal() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+
+ const anotherUri = Services.io.newURI("https://example.com");
+ const anotherPrincipal =
+ Services.scriptSecurityManager.createContentPrincipal(anotherUri, {});
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has been added to the first principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has been added to the second principal"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromPrincipal(
+ principal,
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION,
+ "storageAccessAPI permission has been removed from the first principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has not been removed from the second principal"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
+
+// Test that the storageAccessAPI gets removed from a base domain.
+add_task(async function test_removing_storage_permission_from_base_domainl() {
+ const uri = Services.io.newURI("https://example.net");
+ const principal = Services.scriptSecurityManager.createContentPrincipal(
+ uri,
+ {}
+ );
+ const uriSub = Services.io.newURI("http://test.example.net");
+ const principalSub = Services.scriptSecurityManager.createContentPrincipal(
+ uriSub,
+ {}
+ );
+
+ const anotherUri = Services.io.newURI("https://example.com");
+ const anotherPrincipal =
+ Services.scriptSecurityManager.createContentPrincipal(anotherUri, {});
+
+ Services.perms.addFromPrincipal(
+ principal,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ principalSub,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Services.perms.addFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has been added to the first principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principalSub,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has been added to the subdomain principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has been added to the second principal"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteDataFromBaseDomain(
+ "example.net",
+ true /* user request */,
+ Ci.nsIClearDataService.CLEAR_STORAGE_ACCESS,
+ value => {
+ Assert.equal(value, 0);
+ aResolve();
+ }
+ );
+ });
+
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principal,
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION,
+ "storageAccessAPI permission has been removed from the first principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ principalSub,
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION,
+ "storageAccessAPI permission has been removed from the sub domain principal"
+ );
+ Assert.equal(
+ Services.perms.testExactPermissionFromPrincipal(
+ anotherPrincipal,
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION,
+ "storageAccessAPI permission has not been removed from the second principal"
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
+
+// Tests the deleteUserInteractionForClearingHistory function.
+add_task(async function test_deleteUserInteractionForClearingHistory() {
+ // These should be retained.
+ PermissionTestUtils.add(
+ "https://example.com",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://sub.example.com",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://sub.example.com^userContextId=3",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+
+ // These should be removed.
+ PermissionTestUtils.add(
+ "https://example.org",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://sub.example.org",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+ PermissionTestUtils.add(
+ "https://sub.example.org^userContextId=3",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+
+ let principalWithStorage =
+ Services.scriptSecurityManager.createContentPrincipalFromOrigin(
+ "https://sub.example.com"
+ );
+
+ await new Promise(resolve => {
+ return Services.clearData.deleteUserInteractionForClearingHistory(
+ [principalWithStorage],
+ 0,
+ resolve
+ );
+ });
+
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://example.org",
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://sub.example.org",
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://sub.example.org^userContextId=3",
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION
+ );
+
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://example.com",
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://sub.example.com",
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://sub.example.com^userContextId=3",
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION
+ );
+
+ // This permission is set earlier than the timestamp and should be retained.
+ PermissionTestUtils.add(
+ "https://example.net",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+
+ // Add some time in between taking the snapshot of the timestamp
+ // to avoid flakyness.
+ await new Promise(c => do_timeout(100, c));
+ let timestamp = Date.now();
+ await new Promise(c => do_timeout(100, c));
+
+ // This permission is set later than the timestamp and should be removed.
+ PermissionTestUtils.add(
+ "https://example.org",
+ "storageAccessAPI",
+ Services.perms.ALLOW_ACTION
+ );
+
+ await new Promise(resolve => {
+ return Services.clearData.deleteUserInteractionForClearingHistory(
+ [principalWithStorage],
+ // ClearDataService takes PRTime (microseconds)
+ timestamp * 1000,
+ resolve
+ );
+ });
+
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://example.org",
+ "storageAccessAPI"
+ ),
+ Services.perms.UNKNOWN_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://example.net",
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION
+ );
+ Assert.equal(
+ PermissionTestUtils.testExactPermission(
+ "https://example.com",
+ "storageAccessAPI"
+ ),
+ Services.perms.ALLOW_ACTION
+ );
+
+ await new Promise(aResolve => {
+ Services.clearData.deleteData(
+ Ci.nsIClearDataService.CLEAR_PERMISSIONS,
+ value => aResolve()
+ );
+ });
+});
diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.toml b/toolkit/components/cleardata/tests/unit/xpcshell.toml
new file mode 100644
index 0000000000..2df07abcea
--- /dev/null
+++ b/toolkit/components/cleardata/tests/unit/xpcshell.toml
@@ -0,0 +1,40 @@
+[DEFAULT]
+tags = "condprof"
+firefox-appdir = "browser"
+head = "head.js"
+skip-if = ["os == 'android'"]
+support-files = ""
+prefs = [
+ "privacy.bounceTrackingProtection.enabled=true",
+ "privacy.bounceTrackingProtection.enableTestMode=true",
+ "privacy.bounceTrackingProtection.bounceTrackingPurgeTimerPeriodSec=0",
+]
+
+["test_basic.js"]
+
+["test_bounce_tracking_protection.js"]
+
+["test_certs.js"]
+
+["test_cookie_banner_handling.js"]
+
+["test_cookies.js"]
+
+["test_downloads.js"]
+
+["test_fingerprinting_protection_state.js"]
+
+["test_identity_credential_storage.js"]
+
+["test_network_cache.js"]
+skip-if = ["condprof"] # Bug 1769154 - expected fail w/condprof
+
+["test_passwords.js"]
+
+["test_permissions.js"]
+
+["test_quota.js"]
+
+["test_security_settings.js"]
+
+["test_storage_permission.js"]