diff --git a/browser/base/content/browser-contentblocking.js b/browser/base/content/browser-contentblocking.js index 3450f07bed31..678271c6e914 100644 --- a/browser/base/content/browser-contentblocking.js +++ b/browser/base/content/browser-contentblocking.js @@ -15,6 +15,10 @@ var FastBlock = { XPCOMUtils.defineLazyPreferenceGetter(this, "enabled", this.PREF_ENABLED, false); XPCOMUtils.defineLazyPreferenceGetter(this, "visible", this.PREF_UI_ENABLED, false); }, + + isBlockerActivated(state) { + return state & Ci.nsIWebProgressListener.STATE_BLOCKED_SLOW_TRACKING_CONTENT; + }, }; var TrackingProtection = { @@ -128,6 +132,10 @@ var TrackingProtection = { } } }, + + isBlockerActivated(state) { + return state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT; + }, }; var ThirdPartyCookies = { @@ -154,6 +162,11 @@ var ThirdPartyCookies = { get enabled() { return this.PREF_ENABLED_VALUES.includes(this.behaviorPref); }, + + isBlockerActivated(state) { + return (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_TRACKER) != 0 || + (state & Ci.nsIWebProgressListener.STATE_COOKIES_BLOCKED_FOREIGN) != 0; + }, }; @@ -434,23 +447,21 @@ var ContentBlocking = { this.iconBox.removeAttribute("animate"); } - let isBlocking = state & Ci.nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT; - let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT; - let detected = isBlocking || isAllowing; - - let anyBlockerEnabled = false; + let anyBlockerActivated = false; for (let blocker of this.blockers) { blocker.categoryItem.classList.toggle("blocked", this.enabled && blocker.enabled); blocker.categoryItem.hidden = !blocker.visible; - anyBlockerEnabled = anyBlockerEnabled || blocker.enabled; + anyBlockerActivated = anyBlockerActivated || blocker.isBlockerActivated(state); } - // We consider the shield state "active" when any kind of blocking-related - // activity occurs on the page (blocking or allowing) and at least one blocker - // is enabled. + // We consider the shield state "active" when some kind of blocking activity + // occurs on the page. Note that merely allowing the loading of content that + // we could have blocked does not trigger the appearance of the shield. // This state will be overriden later if there's an exception set for this site. - let active = this.enabled && detected && anyBlockerEnabled; + let active = this.enabled && anyBlockerActivated; + let isAllowing = state & Ci.nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT; + let detected = anyBlockerActivated || isAllowing; let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser); diff --git a/browser/base/content/test/trackingUI/browser.ini b/browser/base/content/test/trackingUI/browser.ini index ba45e89b527c..5bc8d8a6d977 100644 --- a/browser/base/content/test/trackingUI/browser.ini +++ b/browser/base/content/test/trackingUI/browser.ini @@ -3,6 +3,8 @@ tags = trackingprotection support-files = head.js benignPage.html + cookiePage.html + cookieServer.sjs trackingPage.html [browser_trackingUI_3.js] diff --git a/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js b/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js index 8f4adbaf20d7..5e281c263b32 100644 --- a/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js +++ b/browser/base/content/test/trackingUI/browser_trackingUI_pbmode_exceptions.js @@ -75,7 +75,7 @@ function testTrackingPageUnblocked() { ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected"); ok(ContentBlocking.content.hasAttribute("hasException"), "content shows exception"); - ok(ContentBlocking.iconBox.hasAttribute("active"), "shield is active"); + ok(!ContentBlocking.iconBox.hasAttribute("active"), "shield is active"); ok(ContentBlocking.iconBox.hasAttribute("hasException"), "shield shows exception"); is(ContentBlocking.iconBox.getAttribute("tooltiptext"), gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip"), "correct tooltip"); diff --git a/browser/base/content/test/trackingUI/browser_trackingUI_state.js b/browser/base/content/test/trackingUI/browser_trackingUI_state.js index ef4da753883c..5110aedd57b1 100644 --- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js +++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js @@ -18,18 +18,29 @@ const CB_PREF = "browser.contentblocking.enabled"; const CB_UI_PREF = "browser.contentblocking.ui.enabled"; const TP_PREF = "privacy.trackingprotection.enabled"; const TP_PB_PREF = "privacy.trackingprotection.pbmode.enabled"; +const FB_PREF = "browser.fastblock.enabled"; +const FB_TIMEOUT_PREF = "browser.fastblock.timeout"; +const TPC_PREF = "network.cookie.cookieBehavior"; const BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/benignPage.html"; const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html"; +const COOKIE_PAGE = "http://not-tracking.example.com/browser/browser/base/content/test/trackingUI/cookiePage.html"; var ContentBlocking = null; +var FastBlock = null; var TrackingProtection = null; +var ThirdPartyCookies = null; var tabbrowser = null; +var gTrackingPageURL = TRACKING_PAGE; registerCleanupFunction(function() { - TrackingProtection = ContentBlocking = tabbrowser = null; + TrackingProtection = ContentBlocking = FastBlock = + ThirdPartyCookies = tabbrowser = null; UrlClassifierTestUtils.cleanupTestTrackers(); Services.prefs.clearUserPref(TP_PREF); Services.prefs.clearUserPref(TP_PB_PREF); Services.prefs.clearUserPref(CB_PREF); + Services.prefs.clearUserPref(FB_PREF); + Services.prefs.clearUserPref(FB_TIMEOUT_PREF); + Services.prefs.clearUserPref(TPC_PREF); }); // This is a special version of "hidden" that doesn't check for item @@ -98,25 +109,47 @@ function testBenignPageWithException() { } } +function areTrackersBlocked(isPrivateBrowsing) { + let cbEnabled = Services.prefs.getBoolPref(CB_PREF); + let blockedByTP = cbEnabled && + Services.prefs.getBoolPref(isPrivateBrowsing ? TP_PB_PREF : TP_PREF); + let blockedByFB = cbEnabled && + Services.prefs.getBoolPref(FB_PREF) && + // The timeout pref is only checked for completeness, + // checking it is technically unneeded for this test. + Services.prefs.getIntPref(FB_TIMEOUT_PREF) == 0; + let blockedByTPC = cbEnabled && + Services.prefs.getIntPref(TPC_PREF) == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER; + return blockedByTP || blockedByFB || blockedByTPC; +} + function testTrackingPage(window) { info("Tracking content must be blocked"); ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected"); ok(!ContentBlocking.content.hasAttribute("hasException"), "content shows no exception"); - ok(BrowserTestUtils.is_visible(ContentBlocking.iconBox), "icon box is visible"); - ok(ContentBlocking.iconBox.hasAttribute("active"), "shield is active"); + let isPrivateBrowsing = PrivateBrowsingUtils.isWindowPrivate(window); + let blockedByTP = areTrackersBlocked(isPrivateBrowsing); + is(BrowserTestUtils.is_visible(ContentBlocking.iconBox), blockedByTP, + "icon box is" + (blockedByTP ? "" : " not") + " visible"); + is(ContentBlocking.iconBox.hasAttribute("active"), blockedByTP, + "shield is" + (blockedByTP ? "" : " not") + " active"); ok(!ContentBlocking.iconBox.hasAttribute("hasException"), "icon box shows no exception"); is(ContentBlocking.iconBox.getAttribute("tooltiptext"), - gNavigatorBundle.getString("trackingProtection.icon.activeTooltip"), "correct tooltip"); + blockedByTP ? gNavigatorBundle.getString("trackingProtection.icon.activeTooltip") : "", + "correct tooltip"); ok(hidden("#tracking-action-block"), "blockButton is hidden"); + let cbEnabled = Services.prefs.getBoolPref(CB_PREF); if (PrivateBrowsingUtils.isWindowPrivate(window)) { ok(hidden("#tracking-action-unblock"), "unblockButton is hidden"); - ok(!hidden("#tracking-action-unblock-private"), "unblockButtonPrivate is visible"); + is(hidden("#tracking-action-unblock-private"), !cbEnabled, + "unblockButtonPrivate is" + (cbEnabled ? "" : " not") + " visible"); } else { ok(!hidden("#tracking-action-unblock"), "unblockButton is visible"); - ok(hidden("#tracking-action-unblock-private"), "unblockButtonPrivate is hidden"); + is(hidden("#tracking-action-unblock-private"), cbEnabled, + "unblockButtonPrivate is" + (cbEnabled ? "" : " not") + " hidden"); } ok(hidden("#identity-popup-content-blocking-not-detected"), "blocking not detected label is hidden"); @@ -124,25 +157,37 @@ function testTrackingPage(window) { if (Services.prefs.getBoolPref(CB_UI_PREF)) { ok(!hidden("#identity-popup-content-blocking-category-list"), "category list is visible"); - ok(hidden("#identity-popup-content-blocking-category-tracking-protection > .identity-popup-content-blocking-category-add-blocking"), - "TP category item is not showing add blocking"); - ok(!hidden("#identity-popup-content-blocking-category-tracking-protection > .identity-popup-content-blocking-category-state-label"), - "TP category item is set to blocked"); + let category; + if (Services.prefs.getBoolPref(FB_PREF)) { + category = "#identity-popup-content-blocking-category-fastblock"; + } else { + category = Services.prefs.getIntPref(TPC_PREF) == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER ? + "#identity-popup-content-blocking-category-3rdpartycookies" : + "#identity-popup-content-blocking-category-tracking-protection"; + } + is(hidden(category + " > .identity-popup-content-blocking-category-add-blocking"), blockedByTP, + "Category item is" + (blockedByTP ? " not" : "") + " showing add blocking"); + is(hidden(category + " > .identity-popup-content-blocking-category-state-label"), !blockedByTP, + "Category item is" + (blockedByTP ? "" : " not") + " set to blocked"); } } -function testTrackingPageUnblocked() { +function testTrackingPageUnblocked(blockedByTP) { info("Tracking content must be white-listed and not blocked"); ok(ContentBlocking.content.hasAttribute("detected"), "trackers are detected"); ok(ContentBlocking.content.hasAttribute("hasException"), "content shows exception"); - ok(ContentBlocking.iconBox.hasAttribute("active"), "shield is active"); - ok(ContentBlocking.iconBox.hasAttribute("hasException"), "shield shows exception"); + let cbEnabled = Services.prefs.getBoolPref(CB_PREF); + ok(!ContentBlocking.iconBox.hasAttribute("active"), "shield is active"); + is(ContentBlocking.iconBox.hasAttribute("hasException"), cbEnabled, + "shield" + (cbEnabled ? " shows" : " doesn't show") + " exception"); is(ContentBlocking.iconBox.getAttribute("tooltiptext"), gNavigatorBundle.getString("trackingProtection.icon.disabledTooltip"), "correct tooltip"); - ok(BrowserTestUtils.is_visible(ContentBlocking.iconBox), "icon box is visible"); - ok(!hidden("#tracking-action-block"), "blockButton is visible"); + is(BrowserTestUtils.is_visible(ContentBlocking.iconBox), cbEnabled, + "icon box is" + (cbEnabled ? "" : " not") + " visible"); + is(hidden("#tracking-action-block"), !cbEnabled, + "blockButton is" + (cbEnabled ? " not" : "") + " visible"); ok(hidden("#tracking-action-unblock"), "unblockButton is hidden"); ok(!hidden("#identity-popup-content-blocking-disabled-label"), "disabled label is visible"); @@ -151,8 +196,17 @@ function testTrackingPageUnblocked() { if (Services.prefs.getBoolPref(CB_UI_PREF)) { ok(!hidden("#identity-popup-content-blocking-category-list"), "category list is visible"); - ok(hidden("#identity-popup-content-blocking-category-tracking-protection > .identity-popup-content-blocking-category-add-blocking"), - "TP category item is not showing add blocking"); + let category; + if (Services.prefs.getBoolPref(FB_PREF)) { + category = "#identity-popup-content-blocking-category-fastblock"; + } else { + category = Services.prefs.getIntPref(TPC_PREF) == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER ? + "#identity-popup-content-blocking-category-3rdpartycookies" : + "#identity-popup-content-blocking-category-tracking-protection"; + } + is(hidden(category + " > .identity-popup-content-blocking-category-add-blocking"), blockedByTP, + "Category item is" + (blockedByTP ? " not" : "") + " showing add blocking"); + // Always hidden no matter if blockedByTP or not, since we have an exception. ok(hidden("#identity-popup-content-blocking-category-tracking-protection > .identity-popup-content-blocking-category-state-label"), "TP category item is not set to blocked"); } @@ -210,14 +264,15 @@ async function testContentBlockingEnabled(tab) { } info("Load a test page containing tracking elements"); - await promiseTabLoadEvent(tab, TRACKING_PAGE); + await promiseTabLoadEvent(tab, gTrackingPageURL); testTrackingPage(tab.ownerGlobal); info("Disable CB for the page (which reloads the page)"); let tabReloadPromise = promiseTabLoadEvent(tab); clickButton("#tracking-action-unblock"); await tabReloadPromise; - testTrackingPageUnblocked(); + let blockedByTP = areTrackersBlocked(isPrivateBrowsing); + testTrackingPageUnblocked(blockedByTP); info("Re-enable TP for the page (which reloads the page)"); tabReloadPromise = promiseTabLoadEvent(tab); @@ -252,7 +307,7 @@ async function testContentBlockingDisabled(tab) { } info("Load a test page containing tracking elements"); - await promiseTabLoadEvent(tab, TRACKING_PAGE); + await promiseTabLoadEvent(tab, gTrackingPageURL); testTrackingPageWithCBDisabled(); } @@ -269,6 +324,20 @@ add_task(async function testNormalBrowsing() { is(TrackingProtection.enabled, Services.prefs.getBoolPref(TP_PREF), "TP.enabled is based on the original pref value"); + Services.prefs.setBoolPref(FB_PREF, false); + + await testContentBlockingEnabled(tab); + + if (Services.prefs.getBoolPref(CB_UI_PREF)) { + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + } else { + Services.prefs.setBoolPref(TP_PREF, false); + ok(!TrackingProtection.enabled, "TP is disabled after setting the pref"); + } + + await testContentBlockingDisabled(tab); + Services.prefs.setBoolPref(TP_PREF, true); ok(TrackingProtection.enabled, "TP is enabled after setting the pref"); Services.prefs.setBoolPref(CB_PREF, true); @@ -287,6 +356,8 @@ add_task(async function testNormalBrowsing() { await testContentBlockingDisabled(tab); gBrowser.removeCurrentTab(); + + Services.prefs.clearUserPref(FB_PREF); }); add_task(async function testPrivateBrowsing() { @@ -297,6 +368,8 @@ add_task(async function testPrivateBrowsing() { // Set the normal mode pref to false to check the pbmode pref. Services.prefs.setBoolPref(TP_PREF, false); + Services.prefs.setBoolPref(FB_PREF, false); + ContentBlocking = tabbrowser.ownerGlobal.ContentBlocking; ok(ContentBlocking, "CB is attached to the private window"); TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection; @@ -304,6 +377,18 @@ add_task(async function testPrivateBrowsing() { is(TrackingProtection.enabled, Services.prefs.getBoolPref(TP_PB_PREF), "TP.enabled is based on the pb pref value"); + await testContentBlockingEnabled(tab); + + if (Services.prefs.getBoolPref(CB_UI_PREF)) { + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + } else { + Services.prefs.setBoolPref(TP_PREF, false); + ok(!TrackingProtection.enabled, "TP is disabled after setting the pref"); + } + + await testContentBlockingDisabled(tab); + Services.prefs.setBoolPref(TP_PB_PREF, true); ok(TrackingProtection.enabled, "TP is enabled after setting the pref"); Services.prefs.setBoolPref(CB_PREF, true); @@ -322,4 +407,105 @@ add_task(async function testPrivateBrowsing() { await testContentBlockingDisabled(tab); privateWin.close(); + + Services.prefs.clearUserPref(FB_PREF); +}); + +add_task(async function testFastBlock() { + if (!SpecialPowers.getBoolPref(CB_UI_PREF)) { + info("The FastBlock test is disabled when the Content Blocking UI is disabled"); + return; + } + + await UrlClassifierTestUtils.addTestTrackers(); + + tabbrowser = gBrowser; + let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser); + + Services.prefs.setBoolPref(FB_PREF, false); + + ContentBlocking = gBrowser.ownerGlobal.ContentBlocking; + ok(ContentBlocking, "CB is attached to the browser window"); + FastBlock = gBrowser.ownerGlobal.FastBlock; + ok(FastBlock, "TP is attached to the browser window"); + is(FastBlock.enabled, Services.prefs.getBoolPref(FB_PREF), + "FB.enabled is based on the original pref value"); + Services.prefs.setBoolPref(CB_PREF, true); + ok(ContentBlocking.enabled, "CB is enabled after setting the pref"); + + await testContentBlockingEnabled(tab); + + ok(Services.prefs.getBoolPref(CB_UI_PREF), "CB UI must be enabled here"); + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + + await testContentBlockingDisabled(tab); + + Services.prefs.setBoolPref(FB_PREF, true); + Services.prefs.setIntPref(FB_TIMEOUT_PREF, 0); + ok(FastBlock.enabled, "FB is enabled after setting the pref"); + Services.prefs.setBoolPref(CB_PREF, true); + ok(ContentBlocking.enabled, "CB is enabled after setting the pref"); + + await testContentBlockingEnabled(tab); + + ok(Services.prefs.getBoolPref(CB_UI_PREF), "CB UI must be enabled here"); + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + + await testContentBlockingDisabled(tab); + + Services.prefs.clearUserPref(FB_PREF); + Services.prefs.clearUserPref(FB_TIMEOUT_PREF); + gBrowser.removeCurrentTab(); +}); + +add_task(async function testThirdPartyCookies() { + if (!SpecialPowers.getBoolPref(CB_UI_PREF)) { + info("The ThirdPartyCookies test is disabled when the Content Blocking UI is disabled"); + return; + } + + await UrlClassifierTestUtils.addTestTrackers(); + gTrackingPageURL = COOKIE_PAGE; + + Services.prefs.setBoolPref(FB_PREF, false); + + tabbrowser = gBrowser; + let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser); + + ContentBlocking = gBrowser.ownerGlobal.ContentBlocking; + ok(ContentBlocking, "CB is attached to the browser window"); + ThirdPartyCookies = gBrowser.ownerGlobal.ThirdPartyCookies; + ok(ThirdPartyCookies, "TP is attached to the browser window"); + is(ThirdPartyCookies.enabled, + Services.prefs.getIntPref(TPC_PREF) == Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, + "TPC.enabled is based on the original pref value"); + Services.prefs.setBoolPref(CB_PREF, true); + ok(ContentBlocking.enabled, "CB is enabled after setting the pref"); + + await testContentBlockingEnabled(tab); + + ok(Services.prefs.getBoolPref(CB_UI_PREF), "CB UI must be enabled here"); + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + + await testContentBlockingDisabled(tab); + + Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER); + ok(ThirdPartyCookies.enabled, "TPC is enabled after setting the pref"); + Services.prefs.setBoolPref(CB_PREF, true); + ok(ContentBlocking.enabled, "CB is enabled after setting the pref"); + + await testContentBlockingEnabled(tab); + + ok(Services.prefs.getBoolPref(CB_UI_PREF), "CB UI must be enabled here"); + Services.prefs.setBoolPref(CB_PREF, false); + ok(!ContentBlocking.enabled, "CB is disabled after setting the pref"); + + await testContentBlockingDisabled(tab); + + Services.prefs.clearUserPref(FB_PREF); + Services.prefs.clearUserPref(TPC_PREF); + gBrowser.removeCurrentTab(); }); diff --git a/browser/base/content/test/trackingUI/cookiePage.html b/browser/base/content/test/trackingUI/cookiePage.html new file mode 100644 index 000000000000..4df463031cb0 --- /dev/null +++ b/browser/base/content/test/trackingUI/cookiePage.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/browser/base/content/test/trackingUI/cookieServer.sjs b/browser/base/content/test/trackingUI/cookieServer.sjs new file mode 100644 index 000000000000..4c84df3922e3 --- /dev/null +++ b/browser/base/content/test/trackingUI/cookieServer.sjs @@ -0,0 +1,9 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 200); + response.setHeader("Set-Cookie", "foopy=1"); + response.write("cookie served"); +} diff --git a/browser/components/preferences/in-content/privacy.xul b/browser/components/preferences/in-content/privacy.xul index 3db43e9f5eb9..bd3cb49bd759 100644 --- a/browser/components/preferences/in-content/privacy.xul +++ b/browser/components/preferences/in-content/privacy.xul @@ -370,7 +370,6 @@ data-l10n-id="content-blocking-tracking-protection-option-always" flex="1" /> -