diff --git a/browser/components/preferences/tests/siteData/browser.toml b/browser/components/preferences/tests/siteData/browser.toml index 9f4f8306e1d3..b7e6ba1b6de6 100644 --- a/browser/components/preferences/tests/siteData/browser.toml +++ b/browser/components/preferences/tests/siteData/browser.toml @@ -10,6 +10,8 @@ support-files = [ ["browser_clearSiteData.js"] +["browser_clearSiteData_v2.js"] + ["browser_siteData.js"] ["browser_siteData2.js"] diff --git a/browser/components/preferences/tests/siteData/browser_clearSiteData.js b/browser/components/preferences/tests/siteData/browser_clearSiteData.js index 7ae1fda4538f..4924dccfea14 100644 --- a/browser/components/preferences/tests/siteData/browser_clearSiteData.js +++ b/browser/components/preferences/tests/siteData/browser_clearSiteData.js @@ -7,10 +7,6 @@ const { PermissionTestUtils } = ChromeUtils.importESModule( "resource://testing-common/PermissionTestUtils.sys.mjs" ); -let useOldClearHistoryDialog = Services.prefs.getBoolPref( - "privacy.sanitize.useOldClearHistoryDialog" -); - async function testClearData(clearSiteData, clearCache) { PermissionTestUtils.add( TEST_QUOTA_USAGE_ORIGIN, @@ -64,9 +60,7 @@ async function testClearData(clearSiteData, clearCache) { let doc = gBrowser.selectedBrowser.contentDocument; let clearSiteDataButton = doc.getElementById("clearSiteDataButton"); - let url = useOldClearHistoryDialog - ? "chrome://browser/content/preferences/dialogs/clearSiteData.xhtml" - : "chrome://browser/content/sanitize_v2.xhtml"; + let url = "chrome://browser/content/preferences/dialogs/clearSiteData.xhtml"; let dialogOpened = promiseLoadSubDialog(url); clearSiteDataButton.doCommand(); let dialogWin = await dialogOpened; @@ -78,10 +72,8 @@ async function testClearData(clearSiteData, clearCache) { // since we've had cache intermittently changing under our feet. let [, convertedCacheUnit] = DownloadUtils.convertByteUnits(cacheUsage); - let cookiesCheckboxId = useOldClearHistoryDialog - ? "clearSiteData" - : "cookiesAndStorage"; - let cacheCheckboxId = useOldClearHistoryDialog ? "clearCache" : "cache"; + let cookiesCheckboxId = "clearSiteData"; + let cacheCheckboxId = "clearCache"; let clearSiteDataCheckbox = dialogWin.document.getElementById(cookiesCheckboxId); let clearCacheCheckbox = dialogWin.document.getElementById(cacheCheckboxId); @@ -106,28 +98,13 @@ async function testClearData(clearSiteData, clearCache) { clearSiteDataCheckbox.checked = clearSiteData; clearCacheCheckbox.checked = clearCache; - if (!useOldClearHistoryDialog) { - // The new clear history dialog has a seperate checkbox for site settings - let siteSettingsCheckbox = - dialogWin.document.getElementById("siteSettings"); - siteSettingsCheckbox.checked = clearSiteData; - // select clear everything to match the old dialog boxes behaviour for this test - let timespanSelection = dialogWin.document.getElementById( - "sanitizeDurationChoice" - ); - timespanSelection.value = 0; - } // Some additional promises/assertions to wait for // when deleting site data. let acceptPromise; let updatePromise; let cookiesClearedPromise; if (clearSiteData) { - // the new clear history dialog does not have a extra prompt - // to clear site data after clicking clear - if (useOldClearHistoryDialog) { - acceptPromise = BrowserTestUtils.promiseAlertDialogOpen("accept"); - } + acceptPromise = BrowserTestUtils.promiseAlertDialogOpen("accept"); updatePromise = promiseSiteDataManagerSitesUpdated(); cookiesClearedPromise = promiseCookiesCleared(); } @@ -137,7 +114,7 @@ async function testClearData(clearSiteData, clearCache) { let clearButton = dialogWin.document .querySelector("dialog") .getButton("accept"); - if (!clearSiteData && !clearCache && useOldClearHistoryDialog) { + if (!clearSiteData && !clearCache) { // Simulate user input on one of the checkboxes to trigger the event listener for // disabling the clearButton. clearCacheCheckbox.doCommand(); @@ -158,7 +135,7 @@ async function testClearData(clearSiteData, clearCache) { // For site data we display an extra warning dialog, make sure // to accept it. - if (clearSiteData && useOldClearHistoryDialog) { + if (clearSiteData) { await acceptPromise; } @@ -222,6 +199,12 @@ async function testClearData(clearSiteData, clearCache) { await SiteDataManager.removeAll(); } +add_setup(function () { + SpecialPowers.pushPrefEnv({ + set: [["privacy.sanitize.useOldClearHistoryDialog", true]], + }); +}); + // Test opening the "Clear All Data" dialog and cancelling. add_task(async function () { await testClearData(false, false); diff --git a/browser/components/preferences/tests/siteData/browser_clearSiteData_v2.js b/browser/components/preferences/tests/siteData/browser_clearSiteData_v2.js new file mode 100644 index 000000000000..f579bd18e362 --- /dev/null +++ b/browser/components/preferences/tests/siteData/browser_clearSiteData_v2.js @@ -0,0 +1,254 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); + +async function testClearData(clearSiteData, clearCache) { + PermissionTestUtils.add( + TEST_QUOTA_USAGE_ORIGIN, + "persistent-storage", + Services.perms.ALLOW_ACTION + ); + + // Open a test site which saves into appcache. + await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_OFFLINE_URL); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + + // Fill indexedDB with test data. + // Don't wait for the page to load, to register the content event handler as quickly as possible. + // If this test goes intermittent, we might have to tell the page to wait longer before + // firing the event. + BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_QUOTA_USAGE_URL, false); + await BrowserTestUtils.waitForContentEvent( + gBrowser.selectedBrowser, + "test-indexedDB-done", + false, + null, + true + ); + BrowserTestUtils.removeTab(gBrowser.selectedTab); + + // Register some service workers. + await loadServiceWorkerTestPage(TEST_SERVICE_WORKER_URL); + await promiseServiceWorkerRegisteredFor(TEST_SERVICE_WORKER_URL); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + // Test the initial states. + let cacheUsage = await SiteDataManager.getCacheSize(); + let quotaUsage = await SiteDataTestUtils.getQuotaUsage( + TEST_QUOTA_USAGE_ORIGIN + ); + let totalUsage = await SiteDataManager.getTotalUsage(); + Assert.greater(cacheUsage, 0, "The cache usage should not be 0"); + Assert.greater(quotaUsage, 0, "The quota usage should not be 0"); + Assert.greater(totalUsage, 0, "The total usage should not be 0"); + + let initialSizeLabelValue = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + async function () { + let sizeLabel = content.document.getElementById("totalSiteDataSize"); + return sizeLabel.textContent; + } + ); + + let doc = gBrowser.selectedBrowser.contentDocument; + let clearSiteDataButton = doc.getElementById("clearSiteDataButton"); + + let url = "chrome://browser/content/sanitize_v2.xhtml"; + let dialogOpened = promiseLoadSubDialog(url); + clearSiteDataButton.doCommand(); + let dialogWin = await dialogOpened; + + // Convert the usage numbers in the same way the UI does it to assert + // that they're displayed in the dialog. + let [convertedTotalUsage] = DownloadUtils.convertByteUnits(totalUsage); + // For cache we just assert that the right unit (KB, probably) is displayed, + // since we've had cache intermittently changing under our feet. + let [, convertedCacheUnit] = DownloadUtils.convertByteUnits(cacheUsage); + + let cookiesCheckboxId = "cookiesAndStorage"; + let cacheCheckboxId = "cache"; + let clearSiteDataCheckbox = + dialogWin.document.getElementById(cookiesCheckboxId); + let clearCacheCheckbox = dialogWin.document.getElementById(cacheCheckboxId); + // The usage details are filled asynchronously, so we assert that they're present by + // waiting for them to be filled in. + await Promise.all([ + TestUtils.waitForCondition( + () => + clearSiteDataCheckbox.label && + clearSiteDataCheckbox.label.includes(convertedTotalUsage), + "Should show the quota usage" + ), + TestUtils.waitForCondition( + () => + clearCacheCheckbox.label && + clearCacheCheckbox.label.includes(convertedCacheUnit), + "Should show the cache usage" + ), + ]); + + // Check the boxes according to our test input. + clearSiteDataCheckbox.checked = clearSiteData; + clearCacheCheckbox.checked = clearCache; + + // select clear everything to match the old dialog boxes behaviour for this test + let timespanSelection = dialogWin.document.getElementById( + "sanitizeDurationChoice" + ); + timespanSelection.value = 1; + + // Some additional promises/assertions to wait for + // when deleting site data. + let updatePromise; + if (clearSiteData) { + // the new clear history dialog does not have a extra prompt + // to clear site data after clicking clear + updatePromise = promiseSiteDataManagerSitesUpdated(); + } + + let dialogClosed = BrowserTestUtils.waitForEvent(dialogWin, "unload"); + + let clearButton = dialogWin.document + .querySelector("dialog") + .getButton("accept"); + let cancelButton = dialogWin.document + .querySelector("dialog") + .getButton("cancel"); + + if (!clearSiteData && !clearCache) { + // Cancel, since we can't delete anything. + cancelButton.click(); + } else { + // Delete stuff! + clearButton.click(); + } + + await dialogClosed; + + if (clearCache) { + TestUtils.waitForCondition(async function () { + let usage = await SiteDataManager.getCacheSize(); + return usage == 0; + }, "The cache usage should be removed"); + } else { + Assert.greater( + await SiteDataManager.getCacheSize(), + 0, + "The cache usage should not be 0" + ); + } + + if (clearSiteData) { + await updatePromise; + await promiseServiceWorkersCleared(); + + TestUtils.waitForCondition(async function () { + let usage = await SiteDataManager.getTotalUsage(); + return usage == 0; + }, "The total usage should be removed"); + } else { + quotaUsage = await SiteDataTestUtils.getQuotaUsage(TEST_QUOTA_USAGE_ORIGIN); + totalUsage = await SiteDataManager.getTotalUsage(); + Assert.greater(quotaUsage, 0, "The quota usage should not be 0"); + Assert.greater(totalUsage, 0, "The total usage should not be 0"); + } + + if (clearCache || clearSiteData) { + // Check that the size label in about:preferences updates after we cleared data. + await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [{ initialSizeLabelValue }], + async function (opts) { + let sizeLabel = content.document.getElementById("totalSiteDataSize"); + await ContentTaskUtils.waitForCondition( + () => sizeLabel.textContent != opts.initialSizeLabelValue, + "Site data size label should have updated." + ); + } + ); + } + + let permission = PermissionTestUtils.getPermissionObject( + TEST_QUOTA_USAGE_ORIGIN, + "persistent-storage" + ); + is( + clearSiteData ? permission : permission.capability, + clearSiteData ? null : Services.perms.ALLOW_ACTION, + "Should have the correct permission state." + ); + + BrowserTestUtils.removeTab(gBrowser.selectedTab); + await SiteDataManager.removeAll(); +} + +add_setup(function () { + SpecialPowers.pushPrefEnv({ + set: [["privacy.sanitize.useOldClearHistoryDialog", false]], + }); +}); + +// Test opening the "Clear All Data" dialog and cancelling. +add_task(async function testNoSiteDataNoCacheClearing() { + await testClearData(false, false); +}); + +// Test opening the "Clear All Data" dialog and removing all site data. +add_task(async function testSiteDataClearing() { + await testClearData(true, false); +}); + +// Test opening the "Clear All Data" dialog and removing all cache. +add_task(async function testCacheClearing() { + await testClearData(false, true); +}); + +// Test opening the "Clear All Data" dialog and removing everything. +add_task(async function testSiteDataAndCacheClearing() { + await testClearData(true, true); +}); + +// Test clearing persistent storage +add_task(async function testPersistentStorage() { + PermissionTestUtils.add( + TEST_QUOTA_USAGE_ORIGIN, + "persistent-storage", + Services.perms.ALLOW_ACTION + ); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + let doc = gBrowser.selectedBrowser.contentDocument; + let clearSiteDataButton = doc.getElementById("clearSiteDataButton"); + + let url = "chrome://browser/content/sanitize_v2.xhtml"; + let dialogOpened = promiseLoadSubDialog(url); + clearSiteDataButton.doCommand(); + let dialogWin = await dialogOpened; + let dialogClosed = BrowserTestUtils.waitForEvent(dialogWin, "unload"); + + let timespanSelection = dialogWin.document.getElementById( + "sanitizeDurationChoice" + ); + timespanSelection.value = 1; + let clearButton = dialogWin.document + .querySelector("dialog") + .getButton("accept"); + clearButton.click(); + await dialogClosed; + + let permission = PermissionTestUtils.getPermissionObject( + TEST_QUOTA_USAGE_ORIGIN, + "persistent-storage" + ); + is(permission, null, "Should have the correct permission state."); + + BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); diff --git a/extensions/permissions/PermissionManager.cpp b/extensions/permissions/PermissionManager.cpp index be144e2dfe3d..39373653a6b1 100644 --- a/extensions/permissions/PermissionManager.cpp +++ b/extensions/permissions/PermissionManager.cpp @@ -1682,22 +1682,15 @@ NS_IMETHODIMP PermissionManager::AddFromPrincipalAndPersistInPrivateBrowsing( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aPermission) { ENSURE_NOT_CHILD_PROCESS; - NS_ENSURE_ARG_POINTER(aPrincipal); - // We don't add the system principal because it actually has no URI and we - // always allow action for them. - if (aPrincipal->IsSystemPrincipal()) { - return NS_OK; - } - // Null principals can't meaningfully have persisted permissions attached to - // them, so we don't allow adding permissions for them. - if (aPrincipal->GetIsNullPrincipal()) { - return NS_OK; - } + bool isValidPermissionPrincipal = false; + nsresult rv = ShouldHandlePrincipalForPermission(aPrincipal, + isValidPermissionPrincipal); - // Permissions may not be added to expanded principals. - if (IsExpandedPrincipal(aPrincipal)) { - return NS_ERROR_INVALID_ARG; + NS_ENSURE_SUCCESS(rv, rv); + if (!isValidPermissionPrincipal) { + // return early if the principal is invalid for permissions + return rv; } // A modificationTime of zero will cause AddInternal to use now(). @@ -1717,7 +1710,6 @@ PermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, uint32_t aPermission, uint32_t aExpireType, int64_t aExpireTime) { ENSURE_NOT_CHILD_PROCESS; - NS_ENSURE_ARG_POINTER(aPrincipal); NS_ENSURE_TRUE(aExpireType == nsIPermissionManager::EXPIRE_NEVER || aExpireType == nsIPermissionManager::EXPIRE_TIME || aExpireType == nsIPermissionManager::EXPIRE_SESSION || @@ -1729,21 +1721,14 @@ PermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, return NS_OK; } - // We don't add the system principal because it actually has no URI and we - // always allow action for them. - if (aPrincipal->IsSystemPrincipal()) { - return NS_OK; - } + bool isValidPermissionPrincipal = false; + nsresult rv = ShouldHandlePrincipalForPermission(aPrincipal, + isValidPermissionPrincipal); - // Null principals can't meaningfully have persisted permissions attached to - // them, so we don't allow adding permissions for them. - if (aPrincipal->GetIsNullPrincipal()) { - return NS_OK; - } - - // Permissions may not be added to expanded principals. - if (IsExpandedPrincipal(aPrincipal)) { - return NS_ERROR_INVALID_ARG; + NS_ENSURE_SUCCESS(rv, rv); + if (!isValidPermissionPrincipal) { + // return early if the principal is invalid for permissions + return rv; } // A modificationTime of zero will cause AddInternal to use now(). @@ -1753,6 +1738,28 @@ PermissionManager::AddFromPrincipal(nsIPrincipal* aPrincipal, aExpireTime, modificationTime, eNotify, eWriteToDB); } +NS_IMETHODIMP +PermissionManager::TestAddFromPrincipalByTime(nsIPrincipal* aPrincipal, + const nsACString& aType, + uint32_t aPermission, + int64_t aModificationTime) { + ENSURE_NOT_CHILD_PROCESS; + + bool isValidPermissionPrincipal = false; + nsresult rv = ShouldHandlePrincipalForPermission(aPrincipal, + isValidPermissionPrincipal); + + NS_ENSURE_SUCCESS(rv, rv); + if (!isValidPermissionPrincipal) { + // return early if the principal is invalid for permissions + return rv; + } + + return AddInternal(aPrincipal, aType, aPermission, 0, + nsIPermissionManager::EXPIRE_NEVER, 0, aModificationTime, + eNotify, eWriteToDB); +} + nsresult PermissionManager::AddInternal( nsIPrincipal* aPrincipal, const nsACString& aType, uint32_t aPermission, int64_t aID, uint32_t aExpireType, int64_t aExpireTime, @@ -2547,6 +2554,34 @@ NS_IMETHODIMP PermissionManager::GetAllByTypes( aResult); } +nsresult PermissionManager::ShouldHandlePrincipalForPermission( + nsIPrincipal* aPrincipal, bool& aIsPermissionPrincipalValid) { + NS_ENSURE_ARG_POINTER(aPrincipal); + // We don't add the system principal because it actually has no URI and we + // always allow action for them. + if (aPrincipal->IsSystemPrincipal()) { + aIsPermissionPrincipalValid = false; + return NS_OK; + } + + // Null principals can't meaningfully have persisted permissions attached to + // them, so we don't allow adding permissions for them. + if (aPrincipal->GetIsNullPrincipal()) { + aIsPermissionPrincipalValid = false; + return NS_OK; + } + + // Permissions may not be added to expanded principals. + if (IsExpandedPrincipal(aPrincipal)) { + aIsPermissionPrincipalValid = false; + return NS_ERROR_INVALID_ARG; + } + + // Permission principal is valid + aIsPermissionPrincipalValid = true; + return NS_OK; +} + nsresult PermissionManager::GetAllForPrincipalHelper( nsIPrincipal* aPrincipal, bool aSiteScopePermissions, nsTArray>& aResult) { diff --git a/extensions/permissions/PermissionManager.h b/extensions/permissions/PermissionManager.h index ffee6a55041b..f9518c9211d7 100644 --- a/extensions/permissions/PermissionManager.h +++ b/extensions/permissions/PermissionManager.h @@ -401,6 +401,12 @@ class PermissionManager final : public nsIPermissionManager, bool aSiteScopePermissions, nsTArray>& aResult); + // Returns true if the principal can be used for getting / setting + // permissions. If the principal can not be used an error code may be + // returned. + nsresult ShouldHandlePrincipalForPermission( + nsIPrincipal* aPrincipal, bool& aIsPermissionPrincipalValid); + // Returns PermissionHashKey for a given { host, isInBrowserElement } tuple. // This is not simply using PermissionKey because we will walk-up domains in // case of |host| contains sub-domains. Returns null if nothing found. Also diff --git a/netwerk/base/nsIPermissionManager.idl b/netwerk/base/nsIPermissionManager.idl index f234958010d4..e9b990c01919 100644 --- a/netwerk/base/nsIPermissionManager.idl +++ b/netwerk/base/nsIPermissionManager.idl @@ -116,6 +116,14 @@ interface nsIPermissionManager : nsISupports [optional] in uint32_t expireType, [optional] in int64_t expireTime); + /** + * Test method to add a permission for a given principal with custom modification time. + */ + void testAddFromPrincipalByTime(in nsIPrincipal principal, in ACString type, + in uint32_t permission, + in int64_t modificationTime + ); + /** * Add permanent permission information for a given principal in private * browsing. diff --git a/toolkit/components/cleardata/tests/unit/test_storage_permission_clearing.js b/toolkit/components/cleardata/tests/unit/test_storage_permission_clearing.js new file mode 100644 index 000000000000..9285236958e2 --- /dev/null +++ b/toolkit/components/cleardata/tests/unit/test_storage_permission_clearing.js @@ -0,0 +1,271 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/*** + * Tests clearing storage access and persistent storage permissions + */ + +"use strict"; + +const baseDomain = "example.net"; +const baseDomain2 = "host.org"; +const uri = Services.io.newURI(`https://` + baseDomain); +const uri2 = Services.io.newURI(`https://` + baseDomain2); +const uri3 = Services.io.newURI(`https://www.` + baseDomain); +const principal = Services.scriptSecurityManager.createContentPrincipal( + uri, + {} +); +const principal2 = Services.scriptSecurityManager.createContentPrincipal( + uri2, + {} +); +const principal3 = Services.scriptSecurityManager.createContentPrincipal( + uri3, + {} +); + +add_task(async function test_clearing_by_principal() { + Services.perms.addFromPrincipal( + principal, + "storage-access", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "There is a storage-access permission set for principal 1" + ); + + Services.perms.addFromPrincipal( + principal, + "persistent-storage", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "persistent-storage" + ), + Services.perms.ALLOW_ACTION, + "There is a persistent-storage permission set for principal 1" + ); + + // Add a principal that shouldn't get cleared + Services.perms.addFromPrincipal( + principal2, + "storage-access", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "There is a storage-access permission set for principal 2" + ); + + // Add an unrelated permission which we don't expect to be cleared + Services.perms.addFromPrincipal( + principal, + "desktop-notification", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "desktop-notification" + ), + Services.perms.ALLOW_ACTION, + "There is a desktop-notification permission set for principal 1" + ); + + await new Promise(aResolve => { + Services.clearData.deleteDataFromPrincipal( + principal, + true, + Ci.nsIClearDataService.CLEAR_STORAGE_PERMISSIONS, + value => { + Assert.equal(value, 0); + aResolve(); + } + ); + }); + + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.UNKNOWN_ACTION, + "storage-access permission for principal 1 has been removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "persistent-storage" + ), + Services.perms.UNKNOWN_ACTION, + "persistent-storage permission for principal 1 should be removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "storage-access permission for principal 2 should not be removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "desktop-notification" + ), + Services.perms.ALLOW_ACTION, + "desktop-notification permission for principal should not be removed" + ); +}); + +add_task(async function test_clearing_by_baseDomain() { + Services.perms.addFromPrincipal( + principal, + "storage-access", + Services.perms.ALLOW_ACTION + ); + Services.perms.addFromPrincipal( + principal2, + "storage-access", + Services.perms.ALLOW_ACTION + ); + Services.perms.addFromPrincipal( + principal3, + "storage-access", + Services.perms.ALLOW_ACTION + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "There is a storage-access permission set for principal 1" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "There is a storage-access permission set for principal 2" + ); + + await new Promise(aResolve => { + Services.clearData.deleteDataFromBaseDomain( + baseDomain, + true, + Ci.nsIClearDataService.CLEAR_STORAGE_PERMISSIONS, + value => { + Assert.equal(value, 0); + aResolve(); + } + ); + }); + + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.UNKNOWN_ACTION, + "storage-access permission for principal 1 has been removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "storage-access permission for principal 2 should not be removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal3, + "storage-access" + ), + Services.perms.UNKNOWN_ACTION, + "storage-access permission for principal 3 should be removed" + ); +}); + +add_task(async function test_clearing_by_range() { + let currTime = Date.now(); + let modificationTimeTwoHoursAgo = new Date(currTime - 2 * 60 * 60 * 1000); + let modificationTimeThirtyMinsAgo = new Date(currTime - 30 * 60 * 1000); + + Services.perms.testAddFromPrincipalByTime( + principal, + "storage-access", + Services.perms.ALLOW_ACTION, + modificationTimeTwoHoursAgo + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "There is a storage-access permission set for principal 1" + ); + + Services.perms.testAddFromPrincipalByTime( + principal2, + "persistent-storage", + Services.perms.ALLOW_ACTION, + modificationTimeThirtyMinsAgo + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "persistent-storage" + ), + Services.perms.ALLOW_ACTION, + "There is a persistent-storage permission set for principal 2" + ); + + let modificationTimeOneHourAgo = new Date(currTime - 60 * 60 * 1000); + // We need to pass in microseconds to the clear data service + // so we multiply the ranges by 1000 + await new Promise(aResolve => { + Services.clearData.deleteDataInTimeRange( + modificationTimeOneHourAgo * 1000, + Date.now() * 1000, + true, + Ci.nsIClearDataService.CLEAR_STORAGE_PERMISSIONS, + value => { + Assert.equal(value, 0); + aResolve(); + } + ); + }); + + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal, + "storage-access" + ), + Services.perms.ALLOW_ACTION, + "storage-access permission for principal 1 should not be removed" + ); + Assert.equal( + Services.perms.testExactPermissionFromPrincipal( + principal2, + "persistent-storage" + ), + Services.perms.UNKNOWN_ACTION, + "persistent-storage permission for principal 2 should be removed" + ); +}); diff --git a/toolkit/components/cleardata/tests/unit/xpcshell.toml b/toolkit/components/cleardata/tests/unit/xpcshell.toml index 2df07abcea56..bf2813a40130 100644 --- a/toolkit/components/cleardata/tests/unit/xpcshell.toml +++ b/toolkit/components/cleardata/tests/unit/xpcshell.toml @@ -38,3 +38,5 @@ skip-if = ["condprof"] # Bug 1769154 - expected fail w/condprof ["test_security_settings.js"] ["test_storage_permission.js"] + +["test_storage_permission_clearing.js"]