diff options
Diffstat (limited to '')
-rw-r--r-- | browser/components/preferences/tests/browser_contentblocking.js | 1246 |
1 files changed, 1246 insertions, 0 deletions
diff --git a/browser/components/preferences/tests/browser_contentblocking.js b/browser/components/preferences/tests/browser_contentblocking.js new file mode 100644 index 0000000000..d2d214033d --- /dev/null +++ b/browser/components/preferences/tests/browser_contentblocking.js @@ -0,0 +1,1246 @@ +/* eslint-env webextensions */ + +"use strict"; + +const { Preferences } = ChromeUtils.importESModule( + "resource://gre/modules/Preferences.sys.mjs" +); + +const TP_PREF = "privacy.trackingprotection.enabled"; +const TP_PBM_PREF = "privacy.trackingprotection.pbmode.enabled"; +const NCB_PREF = "network.cookie.cookieBehavior"; +const NCBP_PREF = "network.cookie.cookieBehavior.pbmode"; +const CAT_PREF = "browser.contentblocking.category"; +const FP_PREF = "privacy.trackingprotection.fingerprinting.enabled"; +const STP_PREF = "privacy.trackingprotection.socialtracking.enabled"; +const CM_PREF = "privacy.trackingprotection.cryptomining.enabled"; +const LEVEL2_PREF = "privacy.annotate_channels.strict_list.enabled"; +const LEVEL2_PBM_PREF = "privacy.annotate_channels.strict_list.pbmode.enabled"; +const REFERRER_PREF = "network.http.referer.disallowCrossSiteRelaxingDefault"; +const REFERRER_TOP_PREF = + "network.http.referer.disallowCrossSiteRelaxingDefault.top_navigation"; +const OCSP_PREF = "privacy.partition.network_state.ocsp_cache"; +const QUERY_PARAM_STRIP_PREF = "privacy.query_stripping.enabled"; +const QUERY_PARAM_STRIP_PBM_PREF = "privacy.query_stripping.enabled.pbmode"; +const PREF_TEST_NOTIFICATIONS = + "browser.safebrowsing.test-notifications.enabled"; +const STRICT_PREF = "browser.contentblocking.features.strict"; +const PRIVACY_PAGE = "about:preferences#privacy"; +const ISOLATE_UI_PREF = + "browser.contentblocking.reject-and-isolate-cookies.preferences.ui.enabled"; +const FPI_PREF = "privacy.firstparty.isolate"; + +const { EnterprisePolicyTesting, PoliciesPrefTracker } = ChromeUtils.import( + "resource://testing-common/EnterprisePolicyTesting.jsm" +); + +requestLongerTimeout(2); + +add_task(async function testListUpdate() { + SpecialPowers.pushPrefEnv({ set: [[PREF_TEST_NOTIFICATIONS, true]] }); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + + let fingerprintersCheckbox = doc.getElementById( + "contentBlockingFingerprintersCheckbox" + ); + let updateObserved = TestUtils.topicObserved("safebrowsing-update-attempt"); + fingerprintersCheckbox.click(); + let url = (await updateObserved)[1]; + + ok(true, "Has tried to update after the fingerprinting checkbox was toggled"); + is( + url, + "http://127.0.0.1:8888/safebrowsing-dummy/update", + "Using the correct list url to update" + ); + + let cryptominersCheckbox = doc.getElementById( + "contentBlockingCryptominersCheckbox" + ); + updateObserved = TestUtils.topicObserved("safebrowsing-update-attempt"); + cryptominersCheckbox.click(); + url = (await updateObserved)[1]; + + ok(true, "Has tried to update after the cryptomining checkbox was toggled"); + is( + url, + "http://127.0.0.1:8888/safebrowsing-dummy/update", + "Using the correct list url to update" + ); + + gBrowser.removeCurrentTab(); +}); + +// Tests that the content blocking main category checkboxes have the correct default state. +add_task(async function testContentBlockingMainCategory() { + let prefs = [ + [TP_PREF, false], + [TP_PBM_PREF, true], + [STP_PREF, false], + [NCB_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER], + [ + NCBP_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + ], + [ISOLATE_UI_PREF, true], + [FPI_PREF, false], + ]; + + for (let pref of prefs) { + switch (typeof pref[1]) { + case "boolean": + SpecialPowers.setBoolPref(pref[0], pref[1]); + break; + case "number": + SpecialPowers.setIntPref(pref[0], pref[1]); + break; + } + } + + let checkboxes = [ + "#contentBlockingTrackingProtectionCheckbox", + "#contentBlockingBlockCookiesCheckbox", + ]; + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + + for (let selector of checkboxes) { + let element = doc.querySelector(selector); + ok(element, "checkbox " + selector + " exists"); + is( + element.getAttribute("checked"), + "true", + "checkbox " + selector + " is checked" + ); + } + + // Ensure the dependent controls of the tracking protection subsection behave properly. + let tpCheckbox = doc.querySelector(checkboxes[0]); + + let dependentControls = ["#trackingProtectionMenu"]; + let alwaysEnabledControls = [ + "#trackingProtectionMenuDesc", + ".content-blocking-category-name", + "#changeBlockListLink", + ]; + + tpCheckbox.checked = true; + + // Select "Always" under "All Detected Trackers". + let menu = doc.querySelector("#trackingProtectionMenu"); + let always = doc.querySelector( + "#trackingProtectionMenu > menupopup > menuitem[value=always]" + ); + let privateElement = doc.querySelector( + "#trackingProtectionMenu > menupopup > menuitem[value=private]" + ); + menu.selectedItem = always; + ok( + !privateElement.selected, + "The Only in private windows item should not be selected" + ); + ok(always.selected, "The Always item should be selected"); + + // The first time, privacy-pane-tp-ui-updated won't be dispatched since the + // assignment above is a no-op. + + // Ensure the dependent controls are enabled + checkControlState(doc, dependentControls, true); + checkControlState(doc, alwaysEnabledControls, true); + + let promise = TestUtils.topicObserved("privacy-pane-tp-ui-updated"); + tpCheckbox.click(); + + await promise; + ok(!tpCheckbox.checked, "The checkbox should now be unchecked"); + + // Ensure the dependent controls are disabled + checkControlState(doc, dependentControls, false); + checkControlState(doc, alwaysEnabledControls, true); + + // Make sure the selection in the tracking protection submenu persists after + // a few times of checking and unchecking All Detected Trackers. + // Doing this in a loop in order to avoid typing in the unrolled version manually. + // We need to go from the checked state of the checkbox to unchecked back to + // checked again... + for (let i = 0; i < 3; ++i) { + promise = TestUtils.topicObserved("privacy-pane-tp-ui-updated"); + tpCheckbox.click(); + + await promise; + is(tpCheckbox.checked, i % 2 == 0, "The checkbox should now be unchecked"); + is( + privateElement.selected, + i % 2 == 0, + "The Only in private windows item should be selected by default, when the checkbox is checked" + ); + ok(!always.selected, "The Always item should no longer be selected"); + } + + let cookieMenu = doc.querySelector("#blockCookiesMenu"); + let cookieMenuTrackers = cookieMenu.querySelector( + "menupopup > menuitem[value=trackers]" + ); + let cookieMenuTrackersPlusIsolate = cookieMenu.querySelector( + "menupopup > menuitem[value=trackers-plus-isolate]" + ); + let cookieMenuUnvisited = cookieMenu.querySelector( + "menupopup > menuitem[value=unvisited]" + ); + let cookieMenuAllThirdParties = doc.querySelector( + "menupopup > menuitem[value=all-third-parties]" + ); + let cookieMenuAll = cookieMenu.querySelector( + "menupopup > menuitem[value=always]" + ); + // Select block trackers + cookieMenuTrackers.click(); + ok(cookieMenuTrackers.selected, "The trackers item should be selected"); + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER}` + ); + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + // Select block trackers and isolate + cookieMenuTrackersPlusIsolate.click(); + ok( + cookieMenuTrackersPlusIsolate.selected, + "The trackers plus isolate item should be selected" + ); + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + // Select block unvisited + cookieMenuUnvisited.click(); + ok(cookieMenuUnvisited.selected, "The unvisited item should be selected"); + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN}` + ); + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + // Select block all third party + cookieMenuAllThirdParties.click(); + ok( + cookieMenuAllThirdParties.selected, + "The all-third-parties item should be selected" + ); + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN}` + ); + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + // Select block all third party + cookieMenuAll.click(); + ok(cookieMenuAll.selected, "The all cookies item should be selected"); + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT}` + ); + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + + gBrowser.removeCurrentTab(); + + // Ensure the block-trackers-plus-isolate option only shows in the dropdown if the UI pref is set. + Services.prefs.setBoolPref(ISOLATE_UI_PREF, false); + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + doc = gBrowser.contentDocument; + cookieMenuTrackersPlusIsolate = doc.querySelector( + "#blockCookiesMenu menupopup > menuitem[value=trackers-plus-isolate]" + ); + ok( + cookieMenuTrackersPlusIsolate.hidden, + "Trackers plus isolate option is hidden from the dropdown if the ui pref is not set." + ); + + gBrowser.removeCurrentTab(); + + // Ensure the block-trackers-plus-isolate option only shows in the dropdown if FPI is disabled. + SpecialPowers.setIntPref( + NCB_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN + ); + SpecialPowers.setBoolPref(FPI_PREF, true); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + doc = gBrowser.contentDocument; + cookieMenuTrackers = doc.querySelector( + "#blockCookiesMenu menupopup > menuitem[value=trackers]" + ); + cookieMenuTrackersPlusIsolate = doc.querySelector( + "#blockCookiesMenu menupopup > menuitem[value=trackers-plus-isolate]" + ); + ok(cookieMenuTrackers.selected, "The trackers item should be selected"); + ok( + cookieMenuTrackersPlusIsolate.hidden, + "Trackers plus isolate option is hidden from the dropdown if the FPI pref is set." + ); + gBrowser.removeCurrentTab(); + + for (let pref of prefs) { + SpecialPowers.clearUserPref(pref[0]); + } +}); + +// Tests that the content blocking "Standard" category radio sets the prefs to their default values. +add_task(async function testContentBlockingStandardCategory() { + let prefs = { + [TP_PREF]: null, + [TP_PBM_PREF]: null, + [NCB_PREF]: null, + [NCBP_PREF]: null, + [FP_PREF]: null, + [STP_PREF]: null, + [CM_PREF]: null, + [LEVEL2_PREF]: null, + [LEVEL2_PBM_PREF]: null, + [REFERRER_PREF]: null, + [REFERRER_TOP_PREF]: null, + [OCSP_PREF]: null, + [QUERY_PARAM_STRIP_PREF]: null, + [QUERY_PARAM_STRIP_PBM_PREF]: null, + }; + + for (let pref in prefs) { + Services.prefs.clearUserPref(pref); + switch (Services.prefs.getPrefType(pref)) { + case Services.prefs.PREF_BOOL: + prefs[pref] = Services.prefs.getBoolPref(pref); + break; + case Services.prefs.PREF_INT: + prefs[pref] = Services.prefs.getIntPref(pref); + break; + case Services.prefs.PREF_STRING: + prefs[pref] = Services.prefs.getCharPref(pref); + break; + default: + ok(false, `Unknown pref type for ${pref}`); + } + } + + Services.prefs.setBoolPref(TP_PREF, true); + Services.prefs.setBoolPref(TP_PBM_PREF, false); + Services.prefs.setIntPref( + NCB_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER + ); + Services.prefs.setIntPref( + NCBP_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER + ); + Services.prefs.setBoolPref(STP_PREF, !Services.prefs.getBoolPref(STP_PREF)); + Services.prefs.setBoolPref(FP_PREF, !Services.prefs.getBoolPref(FP_PREF)); + Services.prefs.setBoolPref(CM_PREF, !Services.prefs.getBoolPref(CM_PREF)); + Services.prefs.setBoolPref( + LEVEL2_PREF, + !Services.prefs.getBoolPref(LEVEL2_PREF) + ); + Services.prefs.setBoolPref( + LEVEL2_PBM_PREF, + !Services.prefs.getBoolPref(LEVEL2_PBM_PREF) + ); + Services.prefs.setBoolPref( + REFERRER_PREF, + !Services.prefs.getBoolPref(REFERRER_PREF) + ); + Services.prefs.setBoolPref( + REFERRER_TOP_PREF, + !Services.prefs.getBoolPref(REFERRER_TOP_PREF) + ); + Services.prefs.setBoolPref(OCSP_PREF, !Services.prefs.getBoolPref(OCSP_PREF)); + Services.prefs.setBoolPref( + QUERY_PARAM_STRIP_PREF, + !Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PREF) + ); + Services.prefs.setBoolPref( + QUERY_PARAM_STRIP_PBM_PREF, + !Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PBM_PREF) + ); + + for (let pref in prefs) { + switch (Services.prefs.getPrefType(pref)) { + case Services.prefs.PREF_BOOL: + // Account for prefs that may have retained their default value + if (Services.prefs.getBoolPref(pref) != prefs[pref]) { + ok( + Services.prefs.prefHasUserValue(pref), + `modified the pref ${pref}` + ); + } + break; + case Services.prefs.PREF_INT: + if (Services.prefs.getIntPref(pref) != prefs[pref]) { + ok( + Services.prefs.prefHasUserValue(pref), + `modified the pref ${pref}` + ); + } + break; + case Services.prefs.PREF_STRING: + if (Services.prefs.getCharPref(pref) != prefs[pref]) { + ok( + Services.prefs.prefHasUserValue(pref), + `modified the pref ${pref}` + ); + } + break; + default: + ok(false, `Unknown pref type for ${pref}`); + } + } + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + + let standardRadioOption = doc.getElementById("standardRadio"); + standardRadioOption.click(); + + // TP prefs are reset async to check for extensions controlling them. + await TestUtils.waitForCondition( + () => !Services.prefs.prefHasUserValue(TP_PREF) + ); + + for (let pref in prefs) { + ok(!Services.prefs.prefHasUserValue(pref), `reset the pref ${pref}`); + } + is( + Services.prefs.getStringPref(CAT_PREF), + "standard", + `${CAT_PREF} has been set to standard` + ); + + gBrowser.removeCurrentTab(); +}); + +// Tests that the content blocking "Strict" category radio sets the prefs to the expected values. +add_task(async function testContentBlockingStrictCategory() { + Services.prefs.setBoolPref(TP_PREF, false); + Services.prefs.setBoolPref(TP_PBM_PREF, false); + Services.prefs.setBoolPref(LEVEL2_PREF, false); + Services.prefs.setBoolPref(LEVEL2_PBM_PREF, false); + Services.prefs.setBoolPref(REFERRER_PREF, false); + Services.prefs.setBoolPref(REFERRER_TOP_PREF, false); + Services.prefs.setBoolPref(OCSP_PREF, false); + Services.prefs.setBoolPref(QUERY_PARAM_STRIP_PREF, false); + Services.prefs.setBoolPref(QUERY_PARAM_STRIP_PBM_PREF, false); + Services.prefs.setIntPref( + NCB_PREF, + Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN + ); + Services.prefs.setIntPref( + NCBP_PREF, + Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN + ); + let strict_pref = Services.prefs.getStringPref(STRICT_PREF).split(","); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + + let strictRadioOption = doc.getElementById("strictRadio"); + strictRadioOption.click(); + + // TP prefs are reset async to check for extensions controlling them. + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "strict" + ); + // Depending on the definition of the STRICT_PREF, the dependant prefs may have been + // set to varying values. Ensure they have been set according to this definition. + for (let pref of strict_pref) { + switch (pref) { + case "tp": + is( + Services.prefs.getBoolPref(TP_PREF), + true, + `${TP_PREF} has been set to true` + ); + break; + case "-tp": + is( + Services.prefs.getBoolPref(TP_PREF), + false, + `${TP_PREF} has been set to false` + ); + break; + case "tpPrivate": + is( + Services.prefs.getBoolPref(TP_PBM_PREF), + true, + `${TP_PBM_PREF} has been set to true` + ); + break; + case "-tpPrivate": + is( + Services.prefs.getBoolPref(TP_PBM_PREF), + false, + `${TP_PBM_PREF} has been set to false` + ); + break; + case "fp": + is( + Services.prefs.getBoolPref(FP_PREF), + true, + `${FP_PREF} has been set to true` + ); + break; + case "-fp": + is( + Services.prefs.getBoolPref(FP_PREF), + false, + `${FP_PREF} has been set to false` + ); + break; + case "stp": + is( + Services.prefs.getBoolPref(STP_PREF), + true, + `${STP_PREF} has been set to true` + ); + break; + case "-stp": + is( + Services.prefs.getBoolPref(STP_PREF), + false, + `${STP_PREF} has been set to false` + ); + break; + case "cm": + is( + Services.prefs.getBoolPref(CM_PREF), + true, + `${CM_PREF} has been set to true` + ); + break; + case "-cm": + is( + Services.prefs.getBoolPref(CM_PREF), + false, + `${CM_PREF} has been set to false` + ); + break; + case "lvl2": + is( + Services.prefs.getBoolPref(LEVEL2_PREF), + true, + `${CM_PREF} has been set to true` + ); + break; + case "-lvl2": + is( + Services.prefs.getBoolPref(LEVEL2_PREF), + false, + `${CM_PREF} has been set to false` + ); + break; + case "lvl2PBM": + is( + Services.prefs.getBoolPref(LEVEL2_PBM_PREF), + true, + `${CM_PREF} has been set to true` + ); + break; + case "-lvl2PBM": + is( + Services.prefs.getBoolPref(LEVEL2_PBM_PREF), + false, + `${CM_PREF} has been set to false` + ); + break; + case "rp": + is( + Services.prefs.getBoolPref(REFERRER_PREF), + true, + `${REFERRER_PREF} has been set to true` + ); + break; + case "-rp": + is( + Services.prefs.getBoolPref(REFERRER_PREF), + false, + `${REFERRER_PREF} has been set to false` + ); + break; + case "rpTop": + is( + Services.prefs.getBoolPref(REFERRER_TOP_PREF), + true, + `${REFERRER_TOP_PREF} has been set to true` + ); + break; + case "-rpTop": + is( + Services.prefs.getBoolPref(REFERRER_TOP_PREF), + false, + `${REFERRER_TOP_PREF} has been set to false` + ); + break; + case "ocsp": + is( + Services.prefs.getBoolPref(OCSP_PREF), + true, + `${OCSP_PREF} has been set to true` + ); + break; + case "-ocsp": + is( + Services.prefs.getBoolPref(OCSP_PREF), + false, + `${OCSP_PREF} has been set to false` + ); + break; + case "qps": + is( + Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PREF), + true, + `${QUERY_PARAM_STRIP_PREF} has been set to true` + ); + break; + case "-qps": + is( + Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PREF), + false, + `${QUERY_PARAM_STRIP_PREF} has been set to false` + ); + break; + case "qpsPBM": + is( + Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PBM_PREF), + true, + `${QUERY_PARAM_STRIP_PBM_PREF} has been set to true` + ); + break; + case "-qpsPBM": + is( + Services.prefs.getBoolPref(QUERY_PARAM_STRIP_PBM_PREF), + false, + `${QUERY_PARAM_STRIP_PBM_PREF} has been set to false` + ); + break; + case "cookieBehavior0": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_ACCEPT, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_ACCEPT}` + ); + break; + case "cookieBehavior1": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN}` + ); + break; + case "cookieBehavior2": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT}` + ); + break; + case "cookieBehavior3": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN}` + ); + break; + case "cookieBehavior4": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER}` + ); + break; + case "cookieBehavior5": + is( + Services.prefs.getIntPref(NCB_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCB_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + break; + case "cookieBehaviorPBM0": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_ACCEPT, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_ACCEPT}` + ); + break; + case "cookieBehaviorPBM1": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN}` + ); + break; + case "cookieBehaviorPBM2": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT}` + ); + break; + case "cookieBehaviorPBM3": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_LIMIT_FOREIGN}` + ); + break; + case "cookieBehaviorPBM4": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER}` + ); + break; + case "cookieBehaviorPBM5": + is( + Services.prefs.getIntPref(NCBP_PREF), + Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + `${NCBP_PREF} has been set to ${Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN}` + ); + break; + default: + ok(false, "unknown option was added to the strict pref"); + break; + } + } + + gBrowser.removeCurrentTab(); +}); + +// Tests that the content blocking "Custom" category behaves as expected. +add_task(async function testContentBlockingCustomCategory() { + let untouchedPrefs = [ + TP_PREF, + TP_PBM_PREF, + NCB_PREF, + NCBP_PREF, + FP_PREF, + STP_PREF, + CM_PREF, + REFERRER_PREF, + REFERRER_TOP_PREF, + OCSP_PREF, + QUERY_PARAM_STRIP_PREF, + QUERY_PARAM_STRIP_PBM_PREF, + ]; + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + let strictRadioOption = doc.getElementById("strictRadio"); + let standardRadioOption = doc.getElementById("standardRadio"); + let customRadioOption = doc.getElementById("customRadio"); + let defaults = new Preferences({ defaultBranch: true }); + + standardRadioOption.click(); + await TestUtils.waitForCondition( + () => !Services.prefs.prefHasUserValue(TP_PREF) + ); + + customRadioOption.click(); + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "custom" + ); + + // The custom option will only force change of some prefs, like CAT_PREF. All + // other prefs should remain as they were for standard. + for (let pref of untouchedPrefs) { + ok( + !Services.prefs.prefHasUserValue(pref), + `the pref ${pref} remains as default value` + ); + } + + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + strictRadioOption.click(); + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "strict" + ); + + // Changing the following prefs should necessarily set CAT_PREF to "custom" + for (let pref of [ + FP_PREF, + STP_PREF, + CM_PREF, + TP_PREF, + TP_PBM_PREF, + REFERRER_PREF, + REFERRER_TOP_PREF, + OCSP_PREF, + QUERY_PARAM_STRIP_PREF, + QUERY_PARAM_STRIP_PBM_PREF, + ]) { + Services.prefs.setBoolPref(pref, !Services.prefs.getBoolPref(pref)); + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "custom" + ); + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + strictRadioOption.click(); + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "strict" + ); + } + + // Changing the NCB_PREF should necessarily set CAT_PREF to "custom" + let defaultNCB = defaults.get(NCB_PREF); + let nonDefaultNCB; + switch (defaultNCB) { + case Ci.nsICookieService.BEHAVIOR_ACCEPT: + nonDefaultNCB = Ci.nsICookieService.BEHAVIOR_REJECT; + break; + case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER: + case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN: + nonDefaultNCB = Ci.nsICookieService.BEHAVIOR_ACCEPT; + break; + default: + ok( + false, + "Unexpected default value found for " + NCB_PREF + ": " + defaultNCB + ); + break; + } + Services.prefs.setIntPref(NCB_PREF, nonDefaultNCB); + await TestUtils.waitForCondition(() => + Services.prefs.prefHasUserValue(NCB_PREF) + ); + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + strictRadioOption.click(); + await TestUtils.waitForCondition( + () => Services.prefs.getStringPref(CAT_PREF) == "strict" + ); + + // Changing the NCBP_PREF should necessarily set CAT_PREF to "custom" + let defaultNCBP = defaults.get(NCBP_PREF); + let nonDefaultNCBP; + switch (defaultNCBP) { + case Ci.nsICookieService.BEHAVIOR_ACCEPT: + nonDefaultNCBP = Ci.nsICookieService.BEHAVIOR_REJECT; + break; + case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER: + case Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN: + nonDefaultNCBP = Ci.nsICookieService.BEHAVIOR_ACCEPT; + break; + default: + ok( + false, + "Unexpected default value found for " + NCBP_PREF + ": " + defaultNCBP + ); + break; + } + Services.prefs.setIntPref(NCBP_PREF, nonDefaultNCBP); + await TestUtils.waitForCondition(() => + Services.prefs.prefHasUserValue(NCBP_PREF) + ); + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + for (let pref of untouchedPrefs) { + SpecialPowers.clearUserPref(pref); + } + + gBrowser.removeCurrentTab(); +}); + +function checkControlState(doc, controls, enabled) { + for (let selector of controls) { + for (let control of doc.querySelectorAll(selector)) { + if (enabled) { + ok(!control.hasAttribute("disabled"), `${selector} is enabled.`); + } else { + is( + control.getAttribute("disabled"), + "true", + `${selector} is disabled.` + ); + } + } + } +} + +// Checks that the menulists for tracking protection and cookie blocking are disabled when all TP prefs are off. +add_task(async function testContentBlockingDependentTPControls() { + SpecialPowers.pushPrefEnv({ + set: [ + [TP_PREF, false], + [TP_PBM_PREF, false], + [NCB_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT], + [CAT_PREF, "custom"], + ], + }); + + let disabledControls = ["#trackingProtectionMenu", "#blockCookiesMenu"]; + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + checkControlState(doc, disabledControls, false); + + gBrowser.removeCurrentTab(); +}); + +// Checks that social media trackers, cryptomining and fingerprinting visibility +// can be controlled via pref. +add_task(async function testCustomOptionsVisibility() { + Services.prefs.setBoolPref( + "browser.contentblocking.cryptomining.preferences.ui.enabled", + false + ); + Services.prefs.setBoolPref( + "browser.contentblocking.fingerprinting.preferences.ui.enabled", + false + ); + Services.prefs.setBoolPref( + "privacy.socialtracking.block_cookies.enabled", + false + ); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + let doc = gBrowser.contentDocument; + let cryptominersOption = doc.getElementById( + "contentBlockingCryptominersOption" + ); + let fingerprintersOption = doc.getElementById( + "contentBlockingFingerprintersOption" + ); + + ok(cryptominersOption.hidden, "Cryptomining is hidden"); + ok(fingerprintersOption.hidden, "Fingerprinting is hidden"); + + gBrowser.removeCurrentTab(); + + Services.prefs.setBoolPref( + "browser.contentblocking.cryptomining.preferences.ui.enabled", + true + ); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + doc = gBrowser.contentDocument; + cryptominersOption = doc.getElementById("contentBlockingCryptominersOption"); + fingerprintersOption = doc.getElementById( + "contentBlockingFingerprintersOption" + ); + + ok(!cryptominersOption.hidden, "Cryptomining is shown"); + ok(fingerprintersOption.hidden, "Fingerprinting is hidden"); + + gBrowser.removeCurrentTab(); + + Services.prefs.setBoolPref( + "browser.contentblocking.fingerprinting.preferences.ui.enabled", + true + ); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + doc = gBrowser.contentDocument; + cryptominersOption = doc.getElementById("contentBlockingCryptominersOption"); + fingerprintersOption = doc.getElementById( + "contentBlockingFingerprintersOption" + ); + + ok(!cryptominersOption.hidden, "Cryptomining is shown"); + ok(!fingerprintersOption.hidden, "Fingerprinting is shown"); + + gBrowser.removeCurrentTab(); + + // Social media trackers UI should be hidden + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + doc = gBrowser.contentDocument; + let socialTrackingUI = [...doc.querySelectorAll(".social-media-option")]; + + ok( + socialTrackingUI.every(el => el.hidden), + "All Social media tracker UI instances are hidden" + ); + + gBrowser.removeCurrentTab(); + + // Social media trackers UI should be visible + Services.prefs.setBoolPref( + "privacy.socialtracking.block_cookies.enabled", + true + ); + + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + + doc = gBrowser.contentDocument; + socialTrackingUI = [...doc.querySelectorAll(".social-media-option")]; + + ok( + !socialTrackingUI.every(el => el.hidden), + "All Social media tracker UI instances are visible" + ); + + gBrowser.removeCurrentTab(); + + Services.prefs.clearUserPref( + "browser.contentblocking.cryptomining.preferences.ui.enabled" + ); + Services.prefs.clearUserPref( + "browser.contentblocking.fingerprinting.preferences.ui.enabled" + ); + Services.prefs.clearUserPref("privacy.socialtracking.block_cookies.enabled"); +}); + +// Checks that adding a custom enterprise policy will put the user in the custom category. +// Other categories will be disabled. +add_task(async function testPolicyCategorization() { + Services.prefs.setStringPref(CAT_PREF, "standard"); + is( + Services.prefs.getStringPref(CAT_PREF), + "standard", + `${CAT_PREF} starts on standard` + ); + ok( + !Services.prefs.prefHasUserValue(TP_PREF), + `${TP_PREF} starts with the default value` + ); + PoliciesPrefTracker.start(); + + await EnterprisePolicyTesting.setupPolicyEngineWithJson({ + policies: { + EnableTrackingProtection: { + Value: true, + }, + }, + }); + EnterprisePolicyTesting.checkPolicyPref(TP_PREF, true, false); + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + Services.prefs.setStringPref(CAT_PREF, "standard"); + is( + Services.prefs.getStringPref(CAT_PREF), + "standard", + `${CAT_PREF} starts on standard` + ); + ok( + !Services.prefs.prefHasUserValue(NCB_PREF), + `${NCB_PREF} starts with the default value` + ); + ok( + !Services.prefs.prefHasUserValue(NCBP_PREF), + `${NCBP_PREF} starts with the default value` + ); + + let uiUpdatedPromise = TestUtils.topicObserved("privacy-pane-tp-ui-updated"); + await EnterprisePolicyTesting.setupPolicyEngineWithJson({ + policies: { + Cookies: { + AcceptThirdParty: "never", + Locked: true, + }, + }, + }); + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + await uiUpdatedPromise; + + EnterprisePolicyTesting.checkPolicyPref( + NCB_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, + true + ); + EnterprisePolicyTesting.checkPolicyPref( + NCBP_PREF, + Ci.nsICookieService.BEHAVIOR_REJECT_FOREIGN, + true + ); + is( + Services.prefs.getStringPref(CAT_PREF), + "custom", + `${CAT_PREF} has been set to custom` + ); + + let doc = gBrowser.contentDocument; + let strictRadioOption = doc.getElementById("strictRadio"); + let standardRadioOption = doc.getElementById("standardRadio"); + is(strictRadioOption.disabled, true, "the strict option is disabled"); + is(standardRadioOption.disabled, true, "the standard option is disabled"); + + gBrowser.removeCurrentTab(); + + // Cleanup after this particular test. + if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) { + await EnterprisePolicyTesting.setupPolicyEngineWithJson({ + policies: { + Cookies: { + Locked: false, + }, + }, + }); + await EnterprisePolicyTesting.setupPolicyEngineWithJson(""); + } + is( + Services.policies.status, + Ci.nsIEnterprisePolicies.INACTIVE, + "Engine is inactive at the end of the test" + ); + + EnterprisePolicyTesting.resetRunOnceState(); + PoliciesPrefTracker.stop(); +}); + +// Tests that changing a content blocking pref shows the content blocking warning +// to reload tabs to apply changes. +add_task(async function testContentBlockingReloadWarning() { + Services.prefs.setStringPref(CAT_PREF, "standard"); + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + let reloadWarnings = [ + ...doc.querySelectorAll(".content-blocking-warning.reload-tabs"), + ]; + let allHidden = reloadWarnings.every(el => el.hidden); + ok(allHidden, "all of the warnings to reload tabs are initially hidden"); + + Services.prefs.setStringPref(CAT_PREF, "strict"); + + let strictWarning = doc.querySelector( + "#contentBlockingOptionStrict .content-blocking-warning.reload-tabs" + ); + ok( + !BrowserTestUtils.is_hidden(strictWarning), + "The warning in the strict section should be showing" + ); + + Services.prefs.setStringPref(CAT_PREF, "standard"); + gBrowser.removeCurrentTab(); +}); + +// Tests that changing a content blocking pref does not show the content blocking warning +// if it is the only tab. +add_task(async function testContentBlockingReloadWarningSingleTab() { + Services.prefs.setStringPref(CAT_PREF, "standard"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, PRIVACY_PAGE); + await BrowserTestUtils.browserLoaded( + gBrowser.selectedBrowser, + false, + PRIVACY_PAGE + ); + + let reloadWarnings = [ + ...gBrowser.contentDocument.querySelectorAll( + ".content-blocking-warning.reload-tabs" + ), + ]; + ok(reloadWarnings.length, "must have at least one reload warning"); + ok( + reloadWarnings.every(el => el.hidden), + "all of the warnings to reload tabs are initially hidden" + ); + + is(BrowserWindowTracker.windowCount, 1, "There is only one window open"); + is(gBrowser.tabs.length, 1, "There is only one tab open"); + Services.prefs.setStringPref(CAT_PREF, "strict"); + + ok( + reloadWarnings.every(el => el.hidden), + "all of the warnings to reload tabs are still hidden" + ); + Services.prefs.setStringPref(CAT_PREF, "standard"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:newtab"); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); +}); + +// Checks that the reload tabs message reloads all tabs except the active tab. +add_task(async function testReloadTabsMessage() { + Services.prefs.setStringPref(CAT_PREF, "strict"); + let exampleTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://example.com" + ); + let examplePinnedTab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://example.com" + ); + gBrowser.pinTab(examplePinnedTab); + await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true }); + let doc = gBrowser.contentDocument; + let standardWarning = doc.querySelector( + "#contentBlockingOptionStandard .content-blocking-warning.reload-tabs" + ); + let standardReloadButton = doc.querySelector( + "#contentBlockingOptionStandard .reload-tabs-button" + ); + + Services.prefs.setStringPref(CAT_PREF, "standard"); + ok( + !BrowserTestUtils.is_hidden(standardWarning), + "The warning in the standard section should be showing" + ); + + let exampleTabBrowserDiscardedPromise = BrowserTestUtils.waitForEvent( + exampleTab, + "TabBrowserDiscarded" + ); + let examplePinnedTabLoadPromise = BrowserTestUtils.browserLoaded( + examplePinnedTab.linkedBrowser + ); + standardReloadButton.click(); + // The pinned example page had a load event + await examplePinnedTabLoadPromise; + // The other one had its browser discarded + await exampleTabBrowserDiscardedPromise; + + ok( + BrowserTestUtils.is_hidden(standardWarning), + "The warning in the standard section should have hidden after being clicked" + ); + + // cleanup + Services.prefs.setStringPref(CAT_PREF, "standard"); + gBrowser.removeTab(exampleTab); + gBrowser.removeTab(examplePinnedTab); + gBrowser.removeCurrentTab(); +}); |