summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_privacy.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_privacy.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_privacy.js979
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();
+});