/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; ChromeUtils.defineModuleGetter(this, "ExtensionPreferencesManager", "resource://gre/modules/ExtensionPreferencesManager.jsm"); ChromeUtils.defineModuleGetter(this, "Preferences", "resource://gre/modules/Preferences.jsm"); const { createAppInfo, promiseShutdownManager, promiseStartupManager, } = AddonTestUtils; AddonTestUtils.init(this); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"); 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, ...args) => { let data = args[0]; // The second argument is the end of the api name, // e.g., "network.networkPredictionEnabled". let apiObj = args[1].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() { 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": false, }, "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": true, }, "websites.cookieConfig": { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, }; 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; default: ok(false, `Unexpected cookie behavior encountered: ${defaultCookieBehavior}`); break; } async function background() { browser.test.onMessage.addListener(async (msg, ...args) => { let data = args[0]; // The second argument is the end of the api name, // e.g., "network.webRTCIPHandlingPolicy". let apiObj = args[1].split(".").reduce((o, i) => o[i], browser.privacy); let settingData; switch (msg) { case "set": await apiObj.set(data); settingData = await apiObj.get({}); browser.test.sendMessage("settingData", 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(); 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); for (let pref in expected) { equal(Preferences.get(pref), expected[pref], `${pref} set correctly for ${value}`); } } 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": 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": false, }); await testSetting( "network.webRTCIPHandlingPolicy", "disable_non_proxied_udp", { "media.peerconnection.ice.default_address_only": false, "media.peerconnection.ice.no_host": 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": 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.firstPartyIsolate", false, { "privacy.firstparty.isolate": false, }); await testSetting( "websites.firstPartyIsolate", true, { "privacy.firstparty.isolate": 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, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION, }, ); // A missing nonPersistentCookies property should default to false. await testSetting( "websites.cookieConfig", {behavior: "reject_third_party"}, { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_FOREIGN, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: "reject_third_party", nonPersistentCookies: false}, ); // A missing behavior property should reset the pref. await testSetting( "websites.cookieConfig", {nonPersistentCookies: true}, { "network.cookie.cookieBehavior": defaultCookieBehavior, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION, }, {behavior: defaultBehavior, nonPersistentCookies: true}, ); await testSetting( "websites.cookieConfig", {behavior: "reject_all"}, { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: "reject_all", nonPersistentCookies: false}, ); await testSetting( "websites.cookieConfig", {behavior: "allow_visited"}, { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_LIMIT_FOREIGN, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: "allow_visited", nonPersistentCookies: false}, ); await testSetting( "websites.cookieConfig", {behavior: "allow_all"}, { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_ACCEPT, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: "allow_all", nonPersistentCookies: false}, ); await testSetting( "websites.cookieConfig", {nonPersistentCookies: true}, { "network.cookie.cookieBehavior": defaultCookieBehavior, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_SESSION, }, {behavior: defaultBehavior, nonPersistentCookies: true}, ); await testSetting( "websites.cookieConfig", {nonPersistentCookies: false}, { "network.cookie.cookieBehavior": defaultCookieBehavior, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: defaultBehavior, nonPersistentCookies: false}, ); await testSetting( "websites.cookieConfig", {behavior: "reject_trackers"}, { "network.cookie.cookieBehavior": cookieSvc.BEHAVIOR_REJECT_TRACKER, "network.cookie.lifetimePolicy": cookieSvc.ACCEPT_NORMALLY, }, {behavior: "reject_trackers", nonPersistentCookies: false}, ); 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(); });