From f277f6146ca5c434bf9122230fac50eeae4178d5 Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Fri, 18 May 2018 11:36:15 +0200 Subject: [PATCH 01/21] Bug 1462469 - Add a "Clear Cookies and Site Data" footer button to the identity popup. r=nhnt11 This implements a new button in the identity popup that allows users to quickly remove cookies and site data from the sites they're visiting. This uses the SiteDataManager behind the scenes and is similar to the changes we made for PageInfo already. There's a major drawback to this approach in that SiteDataManager needs to refresh its entire data set everytime we want information about a single site or want to remove anything (it's not trivial to get rid of that limitation while dealing with all the quirks of our storage APIs). I will work around this by implementing a way for SiteDataManager to incrementally update itself in bug 1460768. MozReview-Commit-ID: Iy7ia0KllFq --HG-- extra : rebase_source : a36e0e7049c5892464d91ad42c3bf523dd5013f9 --- browser/base/content/browser-siteIdentity.js | 52 +++++++++ browser/base/content/browser.js | 1 + .../content/test/siteIdentity/browser.ini | 1 + .../browser_identityPopup_clearSiteData.js | 110 ++++++++++++++++++ .../controlcenter/content/panel.inc.xul | 12 +- .../locales/en-US/chrome/browser/browser.dtd | 2 + .../themes/shared/controlcenter/panel.inc.css | 13 ++- 7 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js diff --git a/browser/base/content/browser-siteIdentity.js b/browser/base/content/browser-siteIdentity.js index b5263cb12155..ff86f1c4b470 100644 --- a/browser/base/content/browser-siteIdentity.js +++ b/browser/base/content/browser-siteIdentity.js @@ -201,6 +201,10 @@ var gIdentityHandler = { delete this._popupExpander; return this._popupExpander = document.getElementById("identity-popup-security-expander"); }, + get _clearSiteDataFooter() { + delete this._clearSiteDataFooter; + return this._clearSiteDataFooter = document.getElementById("identity-popup-clear-sitedata-footer"); + }, get _permissionAnchors() { delete this._permissionAnchors; let permissionAnchors = {}; @@ -210,6 +214,39 @@ var gIdentityHandler = { return this._permissionAnchors = permissionAnchors; }, + /** + * Handles clicks on the "Clear Cookies and Site Data" button. + */ + async clearSiteData(event) { + if (!this._uriHasHost) { + return; + } + + let host = this._uri.host; + + // Site data could have changed while the identity popup was open, + // reload again to be sure. + await SiteDataManager.updateSites(); + + let baseDomain = SiteDataManager.getBaseDomainFromHost(host); + let siteData = await SiteDataManager.getSites(baseDomain); + + // Hide the popup before showing the removal prompt, to + // avoid a pretty ugly transition. Also hide it even + // if the update resulted in no site data, to keep the + // illusion that clicking the button had an effect. + PanelMultiView.hidePopup(this._identityPopup); + + if (siteData && siteData.length) { + let hosts = siteData.map(site => site.host); + if (SiteDataManager.promptSiteDataRemoval(window, hosts)) { + SiteDataManager.remove(hosts); + } + } + + event.stopPropagation(); + }, + /** * Handler for mouseclicks on the "More Information" button in the * "identity-popup" panel. @@ -578,6 +615,21 @@ var gIdentityHandler = { * applicable */ refreshIdentityPopup() { + // Update cookies and site data information and show the + // "Clear Site Data" button if the site is storing local data. + this._clearSiteDataFooter.hidden = true; + if (this._uriHasHost) { + let host = this._uri.host; + SiteDataManager.updateSites().then(async () => { + let baseDomain = SiteDataManager.getBaseDomainFromHost(host); + let siteData = await SiteDataManager.getSites(baseDomain); + + if (siteData && siteData.length) { + this._clearSiteDataFooter.hidden = false; + } + }); + } + // Update "Learn More" for Mixed Content Blocking and Insecure Login Forms. let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); this._identityPopupMixedContentLearnMore diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 8d00ffd18a65..664aeb49e5b1 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -55,6 +55,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { SchedulePressure: "resource:///modules/SchedulePressure.jsm", ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm", SimpleServiceDiscovery: "resource://gre/modules/SimpleServiceDiscovery.jsm", + SiteDataManager: "resource:///modules/SiteDataManager.jsm", SitePermissions: "resource:///modules/SitePermissions.jsm", TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", diff --git a/browser/base/content/test/siteIdentity/browser.ini b/browser/base/content/test/siteIdentity/browser.ini index 7fda0f959d53..a82067636cb4 100644 --- a/browser/base/content/test/siteIdentity/browser.ini +++ b/browser/base/content/test/siteIdentity/browser.ini @@ -46,6 +46,7 @@ support-files = [browser_identity_UI.js] [browser_identityBlock_focus.js] support-files = ../permissions/permissions.html +[browser_identityPopup_clearSiteData.js] [browser_identityPopup_focus.js] [browser_insecureLoginForms.js] support-files = diff --git a/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js b/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js new file mode 100644 index 000000000000..eb812d2054d6 --- /dev/null +++ b/browser/base/content/test/siteIdentity/browser_identityPopup_clearSiteData.js @@ -0,0 +1,110 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const TEST_ORIGIN = "https://example.com"; +const TEST_SUB_ORIGIN = "https://test1.example.com"; +const REMOVE_DIALOG_URL = "chrome://browser/content/preferences/siteDataRemoveSelected.xul"; + +ChromeUtils.defineModuleGetter(this, "SiteDataTestUtils", + "resource://testing-common/SiteDataTestUtils.jsm"); + +async function testClearing(testQuota, testCookies) { + // Add some test quota storage. + if (testQuota) { + await SiteDataTestUtils.addToIndexedDB(TEST_ORIGIN); + await SiteDataTestUtils.addToIndexedDB(TEST_SUB_ORIGIN); + } + + // Add some test cookies. + if (testCookies) { + SiteDataTestUtils.addToCookies(TEST_ORIGIN, "test1", "1"); + SiteDataTestUtils.addToCookies(TEST_ORIGIN, "test2", "2"); + SiteDataTestUtils.addToCookies(TEST_SUB_ORIGIN, "test3", "1"); + } + + await BrowserTestUtils.withNewTab(TEST_ORIGIN, async function(browser) { + // Verify we have added quota storage. + if (testQuota) { + let usage = await SiteDataTestUtils.getQuotaUsage(TEST_ORIGIN); + Assert.greater(usage, 0, "Should have data for the base origin."); + + usage = await SiteDataTestUtils.getQuotaUsage(TEST_SUB_ORIGIN); + Assert.greater(usage, 0, "Should have data for the sub origin."); + } + + // Open the identity popup. + let { gIdentityHandler } = gBrowser.ownerGlobal; + let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown"); + let siteDataUpdated = TestUtils.topicObserved("sitedatamanager:sites-updated"); + gIdentityHandler._identityBox.click(); + await promisePanelOpen; + await siteDataUpdated; + + let clearFooter = document.getElementById("identity-popup-clear-sitedata-footer"); + let clearButton = document.getElementById("identity-popup-clear-sitedata-button"); + ok(!clearFooter.hidden, "The clear data footer is not hidden."); + + let cookiesCleared; + if (testCookies) { + cookiesCleared = Promise.all([ + TestUtils.topicObserved("cookie-changed", (subj, data) => data == "deleted" && subj.name == "test1"), + TestUtils.topicObserved("cookie-changed", (subj, data) => data == "deleted" && subj.name == "test2"), + TestUtils.topicObserved("cookie-changed", (subj, data) => data == "deleted" && subj.name == "test3"), + ]); + } + + // Click the "Clear data" button. + siteDataUpdated = TestUtils.topicObserved("sitedatamanager:sites-updated"); + let hideEvent = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden"); + let removeDialogPromise = BrowserTestUtils.promiseAlertDialogOpen("accept", REMOVE_DIALOG_URL); + clearButton.click(); + await hideEvent; + await removeDialogPromise; + + await siteDataUpdated; + + // Check that cookies were deleted. + if (testCookies) { + await cookiesCleared; + let uri = Services.io.newURI(TEST_ORIGIN); + is(Services.cookies.countCookiesFromHost(uri.host), 0, "Cookies from the base domain should be cleared"); + uri = Services.io.newURI(TEST_SUB_ORIGIN); + is(Services.cookies.countCookiesFromHost(uri.host), 0, "Cookies from the sub domain should be cleared"); + } + + // Check that quota storage was deleted. + if (testQuota) { + await TestUtils.waitForCondition(async () => { + let usage = await SiteDataTestUtils.getQuotaUsage(TEST_ORIGIN); + return usage == 0; + }, "Should have no data for the base origin."); + + let usage = await SiteDataTestUtils.getQuotaUsage(TEST_SUB_ORIGIN); + is(usage, 0, "Should have no data for the sub origin."); + } + + // Open the site identity panel again to check that the button isn't shown anymore. + promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown"); + siteDataUpdated = TestUtils.topicObserved("sitedatamanager:sites-updated"); + gIdentityHandler._identityBox.click(); + await promisePanelOpen; + await siteDataUpdated; + + ok(clearFooter.hidden, "The clear data footer is hidden after clearing data."); + }); +} + +// Test removing quota managed storage. +add_task(async function test_ClearSiteData() { + await testClearing(true, false); +}); + +// Test removing cookies. +add_task(async function test_ClearCookies() { + await testClearing(false, true); +}); + +// Test removing both. +add_task(async function test_ClearCookiesAndSiteData() { + await testClearing(true, true); +}); diff --git a/browser/components/controlcenter/content/panel.inc.xul b/browser/components/controlcenter/content/panel.inc.xul index 72d6b660f7c2..73da0e4552c4 100644 --- a/browser/components/controlcenter/content/panel.inc.xul +++ b/browser/components/controlcenter/content/panel.inc.xul @@ -95,6 +95,16 @@ &identity.permissionsEmpty; + + +