diff options
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_privacy.js')
-rw-r--r-- | toolkit/components/extensions/test/xpcshell/test_ext_privacy.js | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_privacy.js b/toolkit/components/extensions/test/xpcshell/test_ext_privacy.js new file mode 100644 index 0000000000..1d5f2a8b30 --- /dev/null +++ b/toolkit/components/extensions/test/xpcshell/test_ext_privacy.js @@ -0,0 +1,979 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + ExtensionPreferencesManager: + "resource://gre/modules/ExtensionPreferencesManager.sys.mjs", + Preferences: "resource://gre/modules/Preferences.sys.mjs", +}); + +const { createAppInfo, promiseShutdownManager, promiseStartupManager } = + AddonTestUtils; + +AddonTestUtils.init(this); +AddonTestUtils.overrideCertDB(); + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"); + +// Currently security.tls.version.min has a different default +// value in Nightly and Beta as opposed to Release builds. +const tlsMinPref = Services.prefs.getIntPref("security.tls.version.min"); +if (tlsMinPref != 1 && tlsMinPref != 3) { + ok(false, "This test expects security.tls.version.min set to 1 or 3."); +} +const tlsMinVer = tlsMinPref === 3 ? "TLSv1.2" : "TLSv1"; +const READ_ONLY = true; + +add_task(async function test_privacy() { + // Create an object to hold the values to which we will initialize the prefs. + const SETTINGS = { + "network.networkPredictionEnabled": { + "network.predictor.enabled": true, + "network.prefetch-next": true, + // This pref starts with a numerical value and we need to use whatever the + // default is or we encounter issues when the pref is reset during the test. + "network.http.speculative-parallel-limit": + ExtensionPreferencesManager.getDefaultValue( + "network.http.speculative-parallel-limit" + ), + "network.dns.disablePrefetch": false, + }, + "websites.hyperlinkAuditingEnabled": { + "browser.send_pings": true, + }, + }; + + async function background() { + browser.test.onMessage.addListener(async (msg, data, setting) => { + // The second argument is the end of the api name, + // e.g., "network.networkPredictionEnabled". + let apiObj = setting.split(".").reduce((o, i) => o[i], browser.privacy); + let settingData; + switch (msg) { + case "get": + settingData = await apiObj.get(data); + browser.test.sendMessage("gotData", settingData); + break; + + case "set": + await apiObj.set(data); + settingData = await apiObj.get({}); + browser.test.sendMessage("afterSet", settingData); + break; + + case "clear": + await apiObj.clear(data); + settingData = await apiObj.get({}); + browser.test.sendMessage("afterClear", settingData); + break; + } + }); + } + + // Set prefs to our initial values. + for (let setting in SETTINGS) { + for (let pref in SETTINGS[setting]) { + Preferences.set(pref, SETTINGS[setting][pref]); + } + } + + registerCleanupFunction(() => { + // Reset the prefs. + for (let setting in SETTINGS) { + for (let pref in SETTINGS[setting]) { + Preferences.reset(pref); + } + } + }); + + await promiseStartupManager(); + + // Create an array of extensions to install. + let testExtensions = [ + ExtensionTestUtils.loadExtension({ + background, + manifest: { + permissions: ["privacy"], + }, + useAddonManager: "temporary", + }), + + ExtensionTestUtils.loadExtension({ + background, + manifest: { + permissions: ["privacy"], + }, + useAddonManager: "temporary", + }), + ]; + + for (let extension of testExtensions) { + await extension.startup(); + } + + for (let setting in SETTINGS) { + testExtensions[0].sendMessage("get", {}, setting); + let data = await testExtensions[0].awaitMessage("gotData"); + ok(data.value, "get returns expected value."); + equal( + data.levelOfControl, + "controllable_by_this_extension", + "get returns expected levelOfControl." + ); + + testExtensions[0].sendMessage("get", { incognito: true }, setting); + data = await testExtensions[0].awaitMessage("gotData"); + ok(data.value, "get returns expected value with incognito."); + equal( + data.levelOfControl, + "not_controllable", + "get returns expected levelOfControl with incognito." + ); + + // Change the value to false. + testExtensions[0].sendMessage("set", { value: false }, setting); + data = await testExtensions[0].awaitMessage("afterSet"); + ok(!data.value, "get returns expected value after setting."); + equal( + data.levelOfControl, + "controlled_by_this_extension", + "get returns expected levelOfControl after setting." + ); + + // Verify the prefs have been set to match the "false" setting. + for (let pref in SETTINGS[setting]) { + let msg = `${pref} set correctly for ${setting}`; + if (pref === "network.http.speculative-parallel-limit") { + equal(Preferences.get(pref), 0, msg); + } else { + equal(Preferences.get(pref), !SETTINGS[setting][pref], msg); + } + } + + // Change the value with a newer extension. + testExtensions[1].sendMessage("set", { value: true }, setting); + data = await testExtensions[1].awaitMessage("afterSet"); + ok( + data.value, + "get returns expected value after setting via newer extension." + ); + equal( + data.levelOfControl, + "controlled_by_this_extension", + "get returns expected levelOfControl after setting." + ); + + // Verify the prefs have been set to match the "true" setting. + for (let pref in SETTINGS[setting]) { + let msg = `${pref} set correctly for ${setting}`; + if (pref === "network.http.speculative-parallel-limit") { + equal( + Preferences.get(pref), + ExtensionPreferencesManager.getDefaultValue(pref), + msg + ); + } else { + equal(Preferences.get(pref), SETTINGS[setting][pref], msg); + } + } + + // Change the value with an older extension. + testExtensions[0].sendMessage("set", { value: false }, setting); + data = await testExtensions[0].awaitMessage("afterSet"); + ok(data.value, "Newer extension remains in control."); + equal( + data.levelOfControl, + "controlled_by_other_extensions", + "get returns expected levelOfControl when controlled by other." + ); + + // Clear the value of the newer extension. + testExtensions[1].sendMessage("clear", {}, setting); + data = await testExtensions[1].awaitMessage("afterClear"); + ok(!data.value, "Older extension gains control."); + equal( + data.levelOfControl, + "controllable_by_this_extension", + "Expected levelOfControl returned after clearing." + ); + + testExtensions[0].sendMessage("get", {}, setting); + data = await testExtensions[0].awaitMessage("gotData"); + ok(!data.value, "Current, older extension has control."); + equal( + data.levelOfControl, + "controlled_by_this_extension", + "Expected levelOfControl returned after clearing." + ); + + // Set the value again with the newer extension. + testExtensions[1].sendMessage("set", { value: true }, setting); + data = await testExtensions[1].awaitMessage("afterSet"); + ok( + data.value, + "get returns expected value after setting via newer extension." + ); + equal( + data.levelOfControl, + "controlled_by_this_extension", + "get returns expected levelOfControl after setting." + ); + + // Unload the newer extension. Expect the older extension to regain control. + await testExtensions[1].unload(); + testExtensions[0].sendMessage("get", {}, setting); + data = await testExtensions[0].awaitMessage("gotData"); + ok(!data.value, "Older extension regained control."); + equal( + data.levelOfControl, + "controlled_by_this_extension", + "Expected levelOfControl returned after unloading." + ); + + // Reload the extension for the next iteration of the loop. + testExtensions[1] = ExtensionTestUtils.loadExtension({ + background, + manifest: { + permissions: ["privacy"], + }, + useAddonManager: "temporary", + }); + await testExtensions[1].startup(); + + // Clear the value of the older extension. + testExtensions[0].sendMessage("clear", {}, setting); + data = await testExtensions[0].awaitMessage("afterClear"); + ok(data.value, "Setting returns to original value when all are cleared."); + equal( + data.levelOfControl, + "controllable_by_this_extension", + "Expected levelOfControl returned after clearing." + ); + + // Verify that our initial values were restored. + for (let pref in SETTINGS[setting]) { + equal( + Preferences.get(pref), + SETTINGS[setting][pref], + `${pref} was reset to its initial value.` + ); + } + } + + for (let extension of testExtensions) { + await extension.unload(); + } + + await promiseShutdownManager(); +}); + +add_task(async function test_privacy_other_prefs() { + registerCleanupFunction(() => { + Services.prefs.clearUserPref("security.tls.version.min"); + Services.prefs.clearUserPref("security.tls.version.max"); + }); + + const cookieSvc = Ci.nsICookieService; + + // Create an object to hold the values to which we will initialize the prefs. + const SETTINGS = { + "network.webRTCIPHandlingPolicy": { + "media.peerconnection.ice.default_address_only": false, + "media.peerconnection.ice.no_host": false, + "media.peerconnection.ice.proxy_only_if_behind_proxy": false, + "media.peerconnection.ice.proxy_only": false, + }, + "network.tlsVersionRestriction": { + "security.tls.version.min": tlsMinPref, + "security.tls.version.max": 4, + }, + "network.peerConnectionEnabled": { + "media.peerconnection.enabled": true, + }, + "services.passwordSavingEnabled": { + "signon.rememberSignons": true, + }, + "websites.referrersEnabled": { + "network.http.sendRefererHeader": 2, + }, + "websites.resistFingerprinting": { + "privacy.resistFingerprinting": true, + }, + "websites.firstPartyIsolate": { + "privacy.firstparty.isolate": false, + }, + "websites.cookieConfig": { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT, + }, + }; + + let defaultPrefs = new Preferences({ defaultBranch: true }); + let defaultCookieBehavior = defaultPrefs.get("network.cookie.cookieBehavior"); + let defaultBehavior; + switch (defaultCookieBehavior) { + case cookieSvc.BEHAVIOR_ACCEPT: + defaultBehavior = "allow_all"; + break; + case cookieSvc.BEHAVIOR_REJECT_FOREIGN: + defaultBehavior = "reject_third_party"; + break; + case cookieSvc.BEHAVIOR_REJECT: + defaultBehavior = "reject_all"; + break; + case cookieSvc.BEHAVIOR_LIMIT_FOREIGN: + defaultBehavior = "allow_visited"; + break; + case cookieSvc.BEHAVIOR_REJECT_TRACKER: + defaultBehavior = "reject_trackers"; + break; + case cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN: + defaultBehavior = "reject_trackers_and_partition_foreign"; + break; + default: + ok( + false, + `Unexpected cookie behavior encountered: ${defaultCookieBehavior}` + ); + break; + } + + async function background() { + let listeners = new Set([]); + browser.test.onMessage.addListener(async (msg, data, setting, readOnly) => { + // The second argument is the end of the api name, + // e.g., "network.webRTCIPHandlingPolicy". + let apiObj = setting.split(".").reduce((o, i) => o[i], browser.privacy); + if (msg == "get") { + browser.test.sendMessage("gettingData", await apiObj.get({})); + return; + } + + // Don't add more than one listener per apiName. We leave the + // listener to ensure we do not get more calls than we expect. + if (!listeners.has(setting)) { + apiObj.onChange.addListener(details => { + browser.test.sendMessage("settingData", details); + }); + listeners.add(setting); + } + try { + await apiObj.set(data); + } catch (e) { + browser.test.sendMessage("settingThrowsException", { + message: e.message, + }); + } + // Readonly settings will not trigger onChange, return the setting now. + if (readOnly) { + browser.test.sendMessage("settingData", await apiObj.get({})); + } + }); + } + + // Set prefs to our initial values. + for (let setting in SETTINGS) { + for (let pref in SETTINGS[setting]) { + Preferences.set(pref, SETTINGS[setting][pref]); + } + } + + registerCleanupFunction(() => { + // Reset the prefs. + for (let setting in SETTINGS) { + for (let pref in SETTINGS[setting]) { + Preferences.reset(pref); + } + } + }); + + await promiseStartupManager(); + + let extension = ExtensionTestUtils.loadExtension({ + background, + manifest: { + permissions: ["privacy"], + }, + useAddonManager: "temporary", + }); + + await extension.startup(); + + async function testSetting(setting, value, expected, expectedValue = value) { + extension.sendMessage("set", { value: value }, setting); + let data = await extension.awaitMessage("settingData"); + deepEqual( + data.value, + expectedValue, + `Got expected result on setting ${setting} to ${uneval(value)}` + ); + for (let pref in expected) { + equal( + Preferences.get(pref), + expected[pref], + `${pref} set correctly for ${expected[pref]}` + ); + } + } + + async function testSettingException(setting, value, expected) { + extension.sendMessage("set", { value: value }, setting); + let data = await extension.awaitMessage("settingThrowsException"); + equal(data.message, expected); + } + + async function testGetting(getting, expected, expectedValue) { + extension.sendMessage("get", null, getting); + let data = await extension.awaitMessage("gettingData"); + deepEqual( + data.value, + expectedValue, + `Got expected result on getting ${getting}` + ); + for (let pref in expected) { + equal( + Preferences.get(pref), + expected[pref], + `${pref} get correctly for ${expected[pref]}` + ); + } + } + + await testSetting( + "network.webRTCIPHandlingPolicy", + "default_public_and_private_interfaces", + { + "media.peerconnection.ice.default_address_only": true, + "media.peerconnection.ice.no_host": false, + "media.peerconnection.ice.proxy_only_if_behind_proxy": false, + "media.peerconnection.ice.proxy_only": false, + } + ); + await testSetting( + "network.webRTCIPHandlingPolicy", + "default_public_interface_only", + { + "media.peerconnection.ice.default_address_only": true, + "media.peerconnection.ice.no_host": true, + "media.peerconnection.ice.proxy_only_if_behind_proxy": false, + "media.peerconnection.ice.proxy_only": false, + } + ); + await testSetting( + "network.webRTCIPHandlingPolicy", + "disable_non_proxied_udp", + { + "media.peerconnection.ice.default_address_only": true, + "media.peerconnection.ice.no_host": true, + "media.peerconnection.ice.proxy_only_if_behind_proxy": true, + "media.peerconnection.ice.proxy_only": false, + } + ); + await testSetting("network.webRTCIPHandlingPolicy", "proxy_only", { + "media.peerconnection.ice.default_address_only": false, + "media.peerconnection.ice.no_host": false, + "media.peerconnection.ice.proxy_only_if_behind_proxy": false, + "media.peerconnection.ice.proxy_only": true, + }); + await testSetting("network.webRTCIPHandlingPolicy", "default", { + "media.peerconnection.ice.default_address_only": false, + "media.peerconnection.ice.no_host": false, + "media.peerconnection.ice.proxy_only_if_behind_proxy": false, + "media.peerconnection.ice.proxy_only": false, + }); + + await testSetting("network.peerConnectionEnabled", false, { + "media.peerconnection.enabled": false, + }); + await testSetting("network.peerConnectionEnabled", true, { + "media.peerconnection.enabled": true, + }); + + await testSetting("websites.referrersEnabled", false, { + "network.http.sendRefererHeader": 0, + }); + await testSetting("websites.referrersEnabled", true, { + "network.http.sendRefererHeader": 2, + }); + + await testSetting("websites.resistFingerprinting", false, { + "privacy.resistFingerprinting": false, + }); + await testSetting("websites.resistFingerprinting", true, { + "privacy.resistFingerprinting": true, + }); + + await testSetting("websites.trackingProtectionMode", "always", { + "privacy.trackingprotection.enabled": true, + "privacy.trackingprotection.pbmode.enabled": true, + }); + await testSetting("websites.trackingProtectionMode", "never", { + "privacy.trackingprotection.enabled": false, + "privacy.trackingprotection.pbmode.enabled": false, + }); + await testSetting("websites.trackingProtectionMode", "private_browsing", { + "privacy.trackingprotection.enabled": false, + "privacy.trackingprotection.pbmode.enabled": true, + }); + + await testSetting("services.passwordSavingEnabled", false, { + "signon.rememberSignons": false, + }); + await testSetting("services.passwordSavingEnabled", true, { + "signon.rememberSignons": true, + }); + + await testSetting( + "websites.cookieConfig", + { behavior: "reject_third_party", nonPersistentCookies: true }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_FOREIGN, + }, + { behavior: "reject_third_party", nonPersistentCookies: false } + ); + // A missing nonPersistentCookies property should default to false. + await testSetting( + "websites.cookieConfig", + { behavior: "reject_third_party" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_FOREIGN, + }, + { behavior: "reject_third_party", nonPersistentCookies: false } + ); + // A missing behavior property should reset the pref. + await testSetting( + "websites.cookieConfig", + { nonPersistentCookies: true }, + { + "network.cookie.cookieBehavior": defaultCookieBehavior, + }, + { behavior: defaultBehavior, nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { behavior: "reject_all" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT, + }, + { behavior: "reject_all", nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { behavior: "allow_visited" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_LIMIT_FOREIGN, + }, + { behavior: "allow_visited", nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { behavior: "allow_all" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT, + }, + { behavior: "allow_all", nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { nonPersistentCookies: true }, + { + "network.cookie.cookieBehavior": defaultCookieBehavior, + }, + { behavior: defaultBehavior, nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { nonPersistentCookies: false }, + { + "network.cookie.cookieBehavior": defaultCookieBehavior, + }, + { behavior: defaultBehavior, nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { behavior: "reject_trackers" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_TRACKER, + }, + { behavior: "reject_trackers", nonPersistentCookies: false } + ); + await testSetting( + "websites.cookieConfig", + { behavior: "reject_trackers_and_partition_foreign" }, + { + "network.cookie.cookieBehavior": + cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + }, + { + behavior: "reject_trackers_and_partition_foreign", + nonPersistentCookies: false, + } + ); + + // 1. Can't enable FPI when cookie behavior is "reject_trackers_and_partition_foreign" + await testSettingException( + "websites.firstPartyIsolate", + true, + "Can't enable firstPartyIsolate when cookieBehavior is 'reject_trackers_and_partition_foreign'" + ); + + // 2. Change cookieConfig to reject_trackers should work normally. + await testSetting( + "websites.cookieConfig", + { behavior: "reject_trackers" }, + { + "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_TRACKER, + }, + { behavior: "reject_trackers", nonPersistentCookies: false } + ); + + // 3. Enable FPI + await testSetting("websites.firstPartyIsolate", true, { + "privacy.firstparty.isolate": true, + }); + + // 4. When FPI is enabled, change setting to "reject_trackers_and_partition_foreign" is invalid + await testSettingException( + "websites.cookieConfig", + { behavior: "reject_trackers_and_partition_foreign" }, + "Invalid cookieConfig 'reject_trackers_and_partition_foreign' when firstPartyIsolate is enabled" + ); + + // 5. Set conflict settings manually and check prefs. + Preferences.set("network.cookie.cookieBehavior", 5); + await testGetting( + "websites.firstPartyIsolate", + { "privacy.firstparty.isolate": true }, + true + ); + await testGetting( + "websites.cookieConfig", + { + "network.cookie.cookieBehavior": + cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + }, + { + behavior: "reject_trackers_and_partition_foreign", + nonPersistentCookies: false, + } + ); + + // 6. It is okay to set current saved value. + await testSetting("websites.firstPartyIsolate", true, { + "privacy.firstparty.isolate": true, + }); + await testSetting( + "websites.cookieConfig", + { behavior: "reject_trackers_and_partition_foreign" }, + { + "network.cookie.cookieBehavior": + cookieSvc.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN, + }, + { + behavior: "reject_trackers_and_partition_foreign", + nonPersistentCookies: false, + } + ); + + await testSetting("websites.firstPartyIsolate", false, { + "privacy.firstparty.isolate": false, + }); + + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.2", + maximum: "TLSv1.3", + }, + { + "security.tls.version.min": 3, + "security.tls.version.max": 4, + } + ); + + // Single values + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.3", + }, + { + "security.tls.version.min": 4, + "security.tls.version.max": 4, + }, + { + minimum: "TLSv1.3", + maximum: "TLSv1.3", + } + ); + + // Single values + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.3", + }, + { + "security.tls.version.min": 4, + "security.tls.version.max": 4, + }, + { + minimum: "TLSv1.3", + maximum: "TLSv1.3", + } + ); + + // Invalid values. + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "invalid", + maximum: "invalid", + }, + "Setting TLS version invalid is not allowed for security reasons." + ); + + // Invalid values. + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "invalid2", + }, + "Setting TLS version invalid2 is not allowed for security reasons." + ); + + // Invalid values. + await testSettingException( + "network.tlsVersionRestriction", + { + maximum: "invalid3", + }, + "Setting TLS version invalid3 is not allowed for security reasons." + ); + + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.2", + }, + { + "security.tls.version.min": 3, + "security.tls.version.max": 4, + }, + { + minimum: "TLSv1.2", + maximum: "TLSv1.3", + } + ); + + await testSetting( + "network.tlsVersionRestriction", + { + maximum: "TLSv1.2", + }, + { + "security.tls.version.min": tlsMinPref, + "security.tls.version.max": 3, + }, + { + minimum: tlsMinVer, + maximum: "TLSv1.2", + } + ); + + // Not supported version. + if (tlsMinPref === 3) { + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "TLSv1", + }, + "Setting TLS version TLSv1 is not allowed for security reasons." + ); + + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.1", + }, + "Setting TLS version TLSv1.1 is not allowed for security reasons." + ); + + await testSettingException( + "network.tlsVersionRestriction", + { + maximum: "TLSv1", + }, + "Setting TLS version TLSv1 is not allowed for security reasons." + ); + + await testSettingException( + "network.tlsVersionRestriction", + { + maximum: "TLSv1.1", + }, + "Setting TLS version TLSv1.1 is not allowed for security reasons." + ); + } + + // Min vs Max + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.3", + maximum: "TLSv1.2", + }, + "Setting TLS min version grater than the max version is not allowed." + ); + + // Min vs Max (with default max) + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.2", + maximum: "TLSv1.2", + }, + { + "security.tls.version.min": 3, + "security.tls.version.max": 3, + } + ); + await testSettingException( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.3", + }, + "Setting TLS min version grater than the max version is not allowed." + ); + + // Max vs Min + await testSetting( + "network.tlsVersionRestriction", + { + minimum: "TLSv1.3", + maximum: "TLSv1.3", + }, + { + "security.tls.version.min": 4, + "security.tls.version.max": 4, + } + ); + await testSettingException( + "network.tlsVersionRestriction", + { + maximum: "TLSv1.2", + }, + "Setting TLS max version lower than the min version is not allowed." + ); + + // Empty value. + await testSetting( + "network.tlsVersionRestriction", + {}, + { + "security.tls.version.min": tlsMinPref, + "security.tls.version.max": 4, + }, + { + minimum: tlsMinVer, + maximum: "TLSv1.3", + } + ); + + const GLOBAL_PRIVACY_CONTROL_PREF_NAME = + "privacy.globalprivacycontrol.enabled"; + + Preferences.set(GLOBAL_PRIVACY_CONTROL_PREF_NAME, false); + await testGetting("network.globalPrivacyControl", {}, false); + + Preferences.set(GLOBAL_PRIVACY_CONTROL_PREF_NAME, true); + await testGetting("network.globalPrivacyControl", {}, true); + + // trying to "set" should have no effect when readonly! + extension.sendMessage( + "set", + { value: !Preferences.get(GLOBAL_PRIVACY_CONTROL_PREF_NAME) }, + "network.globalPrivacyControl", + READ_ONLY + ); + let readOnlyGPCData = await extension.awaitMessage("settingData"); + equal( + readOnlyGPCData.value, + Preferences.get(GLOBAL_PRIVACY_CONTROL_PREF_NAME), + "extension cannot set globalPrivacyControl" + ); + + equal(Preferences.get(GLOBAL_PRIVACY_CONTROL_PREF_NAME), true); + + const HTTPS_ONLY_PREF_NAME = "dom.security.https_only_mode"; + const HTTPS_ONLY_PBM_PREF_NAME = "dom.security.https_only_mode_pbm"; + + Preferences.set(HTTPS_ONLY_PREF_NAME, false); + Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, false); + await testGetting("network.httpsOnlyMode", {}, "never"); + + Preferences.set(HTTPS_ONLY_PREF_NAME, true); + Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, false); + await testGetting("network.httpsOnlyMode", {}, "always"); + + Preferences.set(HTTPS_ONLY_PREF_NAME, false); + Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, true); + await testGetting("network.httpsOnlyMode", {}, "private_browsing"); + + // Please note that if https_only_mode = true, then + // https_only_mode_pbm has no effect. + Preferences.set(HTTPS_ONLY_PREF_NAME, true); + Preferences.set(HTTPS_ONLY_PBM_PREF_NAME, true); + await testGetting("network.httpsOnlyMode", {}, "always"); + + // trying to "set" should have no effect when readonly! + extension.sendMessage( + "set", + { value: "never" }, + "network.httpsOnlyMode", + READ_ONLY + ); + let readOnlyData = await extension.awaitMessage("settingData"); + equal(readOnlyData.value, "always"); + + equal(Preferences.get(HTTPS_ONLY_PREF_NAME), true); + equal(Preferences.get(HTTPS_ONLY_PBM_PREF_NAME), true); + + await extension.unload(); + + await promiseShutdownManager(); +}); + +add_task(async function test_exceptions() { + async function background() { + await browser.test.assertRejects( + browser.privacy.network.networkPredictionEnabled.set({ + value: true, + scope: "regular_only", + }), + "Firefox does not support the regular_only settings scope.", + "Expected rejection calling set with invalid scope." + ); + + await browser.test.assertRejects( + browser.privacy.network.networkPredictionEnabled.clear({ + scope: "incognito_persistent", + }), + "Firefox does not support the incognito_persistent settings scope.", + "Expected rejection calling clear with invalid scope." + ); + + browser.test.notifyPass("exceptionTests"); + } + + let extension = ExtensionTestUtils.loadExtension({ + background, + manifest: { + permissions: ["privacy"], + }, + }); + + await extension.startup(); + await extension.awaitFinish("exceptionTests"); + await extension.unload(); +}); |