summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js620
1 files changed, 620 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js b/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
new file mode 100644
index 0000000000..968f76ee28
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_proxy_config.js
@@ -0,0 +1,620 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ Preferences: "resource://gre/modules/Preferences.sys.mjs",
+});
+
+const { ExtensionPermissions } = ChromeUtils.importESModule(
+ "resource://gre/modules/ExtensionPermissions.sys.mjs"
+);
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "42"
+);
+
+// Start a server for `pac.example.com` to intercept attempts to connect to it
+// to load a PAC URL. We won't serve anything, but this prevents attempts at
+// non-local connections if this domain is registered.
+AddonTestUtils.createHttpServer({ hosts: ["pac.example.com"] });
+
+add_setup(async function () {
+ // Bug 1646182: Force ExtensionPermissions to run in rkv mode, the legacy
+ // storage mode will run in xpcshell-legacy-ep.toml
+ await ExtensionPermissions._uninit();
+
+ Services.prefs.setBoolPref(
+ "extensions.webextOptionalPermissionPrompts",
+ false
+ );
+ registerCleanupFunction(() => {
+ Services.prefs.clearUserPref("extensions.webextOptionalPermissionPrompts");
+ });
+
+ await AddonTestUtils.promiseStartupManager();
+});
+
+add_task(async function test_browser_settings() {
+ // TODO bug 1725981: proxy.settings is not supported on Android.
+ if (AppConstants.platform === "android") {
+ info("proxy.settings not supported on Android; skipping");
+ return;
+ }
+
+ const proxySvc = Ci.nsIProtocolProxyService;
+
+ // Create an object to hold the values to which we will initialize the prefs.
+ const PREFS = {
+ "network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
+ "network.proxy.http": "",
+ "network.proxy.http_port": 0,
+ "network.proxy.share_proxy_settings": false,
+ "network.proxy.ssl": "",
+ "network.proxy.ssl_port": 0,
+ "network.proxy.socks": "",
+ "network.proxy.socks_port": 0,
+ "network.proxy.socks_version": 5,
+ "network.proxy.socks_remote_dns": false,
+ "network.proxy.no_proxies_on": "",
+ "network.proxy.autoconfig_url": "",
+ "signon.autologin.proxy": false,
+ };
+
+ async function background() {
+ browser.test.onMessage.addListener(async (msg, value) => {
+ let apiObj = browser.proxy.settings;
+ let result = await apiObj.set({ value });
+ if (msg === "set") {
+ browser.test.assertTrue(result, "set returns true.");
+ browser.test.sendMessage("settingData", await apiObj.get({}));
+ } else {
+ browser.test.assertFalse(result, "set returns false for a no-op.");
+ browser.test.sendMessage("no-op set");
+ }
+ });
+ }
+
+ // Set prefs to our initial values.
+ for (let pref in PREFS) {
+ Preferences.set(pref, PREFS[pref]);
+ }
+
+ registerCleanupFunction(() => {
+ // Reset the prefs.
+ for (let pref in PREFS) {
+ Preferences.reset(pref);
+ }
+ });
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ permissions: ["proxy"],
+ },
+ incognitoOverride: "spanning",
+ useAddonManager: "temporary",
+ });
+
+ await extension.startup();
+
+ async function testSetting(value, expected, expectedValue = value) {
+ extension.sendMessage("set", value);
+ let data = await extension.awaitMessage("settingData");
+ deepEqual(data.value, expectedValue, `The setting has the expected value.`);
+ equal(
+ data.levelOfControl,
+ "controlled_by_this_extension",
+ `The setting has the expected levelOfControl.`
+ );
+ for (let pref in expected) {
+ equal(
+ Preferences.get(pref),
+ expected[pref],
+ `${pref} set correctly for ${value}`
+ );
+ }
+ }
+
+ async function testProxy(config, expectedPrefs, expectedConfig = config) {
+ let proxyConfig = {
+ proxyType: "none",
+ autoConfigUrl: "",
+ autoLogin: false,
+ proxyDNS: false,
+ httpProxyAll: false,
+ socksVersion: 5,
+ passthrough: "",
+ http: "",
+ ssl: "",
+ socks: "",
+ respectBeConservative: true,
+ };
+
+ expectedConfig.proxyType = expectedConfig.proxyType || "system";
+
+ return testSetting(
+ config,
+ expectedPrefs,
+ Object.assign(proxyConfig, expectedConfig)
+ );
+ }
+
+ await testProxy(
+ { proxyType: "none" },
+ { "network.proxy.type": proxySvc.PROXYCONFIG_DIRECT }
+ );
+
+ await testProxy(
+ {
+ proxyType: "autoDetect",
+ autoLogin: true,
+ proxyDNS: true,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_WPAD,
+ "signon.autologin.proxy": true,
+ "network.proxy.socks_remote_dns": true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "system",
+ autoLogin: false,
+ proxyDNS: false,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
+ "signon.autologin.proxy": false,
+ "network.proxy.socks_remote_dns": false,
+ }
+ );
+
+ // Verify that proxyType is optional and it defaults to "system".
+ await testProxy(
+ {
+ autoLogin: false,
+ proxyDNS: false,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_SYSTEM,
+ "signon.autologin.proxy": false,
+ "network.proxy.socks_remote_dns": false,
+ "network.http.proxy.respect-be-conservative": true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "autoConfig",
+ autoConfigUrl: "http://pac.example.com",
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_PAC,
+ "network.proxy.autoconfig_url": "http://pac.example.com",
+ "network.http.proxy.respect-be-conservative": true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "http://www.mozilla.org",
+ autoConfigUrl: "",
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 80,
+ "network.proxy.autoconfig_url": "",
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:80",
+ autoConfigUrl: "",
+ }
+ );
+
+ // When using proxyAll, we expect all proxies to be set to
+ // be the same as http.
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "http://www.mozilla.org:8080",
+ httpProxyAll: true,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 8080,
+ "network.proxy.ssl": "www.mozilla.org",
+ "network.proxy.ssl_port": 8080,
+ "network.proxy.share_proxy_settings": true,
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:8080",
+ ssl: "www.mozilla.org:8080",
+ socks: "",
+ httpProxyAll: true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:8080",
+ httpProxyAll: false,
+ ftp: "www.mozilla.org:8081",
+ ssl: "www.mozilla.org:8082",
+ socks: "mozilla.org:8083",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: true,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 8080,
+ "network.proxy.share_proxy_settings": false,
+ "network.proxy.ssl": "www.mozilla.org",
+ "network.proxy.ssl_port": 8082,
+ "network.proxy.socks": "mozilla.org",
+ "network.proxy.socks_port": 8083,
+ "network.proxy.socks_version": 4,
+ "network.proxy.no_proxies_on": ".mozilla.org",
+ "network.http.proxy.respect-be-conservative": true,
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:8080",
+ httpProxyAll: false,
+ // ftp: "www.mozilla.org:8081", // This line should not be sent back
+ ssl: "www.mozilla.org:8082",
+ socks: "mozilla.org:8083",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "http://www.mozilla.org",
+ ssl: "https://www.mozilla.org",
+ socks: "mozilla.org",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: false,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 80,
+ "network.proxy.share_proxy_settings": false,
+ "network.proxy.ssl": "www.mozilla.org",
+ "network.proxy.ssl_port": 443,
+ "network.proxy.socks": "mozilla.org",
+ "network.proxy.socks_port": 1080,
+ "network.proxy.socks_version": 4,
+ "network.proxy.no_proxies_on": ".mozilla.org",
+ "network.http.proxy.respect-be-conservative": false,
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:80",
+ httpProxyAll: false,
+ ssl: "www.mozilla.org:443",
+ socks: "mozilla.org:1080",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: false,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "http://www.mozilla.org:80",
+ ssl: "https://www.mozilla.org:443",
+ socks: "mozilla.org:1080",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: true,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 80,
+ "network.proxy.share_proxy_settings": false,
+ "network.proxy.ssl": "www.mozilla.org",
+ "network.proxy.ssl_port": 443,
+ "network.proxy.socks": "mozilla.org",
+ "network.proxy.socks_port": 1080,
+ "network.proxy.socks_version": 4,
+ "network.proxy.no_proxies_on": ".mozilla.org",
+ "network.http.proxy.respect-be-conservative": true,
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:80",
+ httpProxyAll: false,
+ ssl: "www.mozilla.org:443",
+ socks: "mozilla.org:1080",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: true,
+ }
+ );
+
+ await testProxy(
+ {
+ proxyType: "manual",
+ http: "http://www.mozilla.org:80",
+ ssl: "https://www.mozilla.org:80",
+ socks: "mozilla.org:80",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: false,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_MANUAL,
+ "network.proxy.http": "www.mozilla.org",
+ "network.proxy.http_port": 80,
+ "network.proxy.share_proxy_settings": false,
+ "network.proxy.ssl": "www.mozilla.org",
+ "network.proxy.ssl_port": 80,
+ "network.proxy.socks": "mozilla.org",
+ "network.proxy.socks_port": 80,
+ "network.proxy.socks_version": 4,
+ "network.proxy.no_proxies_on": ".mozilla.org",
+ "network.http.proxy.respect-be-conservative": false,
+ },
+ {
+ proxyType: "manual",
+ http: "www.mozilla.org:80",
+ httpProxyAll: false,
+ ssl: "www.mozilla.org:80",
+ socks: "mozilla.org:80",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ respectBeConservative: false,
+ }
+ );
+
+ // Test resetting values.
+ await testProxy(
+ {
+ proxyType: "none",
+ http: "",
+ ssl: "",
+ socks: "",
+ socksVersion: 5,
+ passthrough: "",
+ respectBeConservative: true,
+ },
+ {
+ "network.proxy.type": proxySvc.PROXYCONFIG_DIRECT,
+ "network.proxy.http": "",
+ "network.proxy.http_port": 0,
+ "network.proxy.ssl": "",
+ "network.proxy.ssl_port": 0,
+ "network.proxy.socks": "",
+ "network.proxy.socks_port": 0,
+ "network.proxy.socks_version": 5,
+ "network.proxy.no_proxies_on": "",
+ "network.http.proxy.respect-be-conservative": true,
+ }
+ );
+
+ await extension.unload();
+});
+
+add_task(async function test_bad_value_proxy_config() {
+ let background =
+ AppConstants.platform === "android"
+ ? async () => {
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "none",
+ },
+ }),
+ /proxy.settings is not supported on android/,
+ "proxy.settings.set rejects on Android."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.get({}),
+ /proxy.settings is not supported on android/,
+ "proxy.settings.get rejects on Android."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.clear({}),
+ /proxy.settings is not supported on android/,
+ "proxy.settings.clear rejects on Android."
+ );
+
+ browser.test.sendMessage("done");
+ }
+ : async () => {
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "abc",
+ },
+ }),
+ /abc is not a valid value for proxyType/,
+ "proxy.settings.set rejects with an invalid proxyType value."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "autoConfig",
+ },
+ }),
+ /undefined is not a valid value for autoConfigUrl/,
+ "proxy.settings.set for type autoConfig rejects with an empty autoConfigUrl value."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "autoConfig",
+ autoConfigUrl: "abc",
+ },
+ }),
+ /abc is not a valid value for autoConfigUrl/,
+ "proxy.settings.set rejects with an invalid autoConfigUrl value."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "manual",
+ socksVersion: "abc",
+ },
+ }),
+ /abc is not a valid value for socksVersion/,
+ "proxy.settings.set rejects with an invalid socksVersion value."
+ );
+
+ await browser.test.assertRejects(
+ browser.proxy.settings.set({
+ value: {
+ proxyType: "manual",
+ socksVersion: 3,
+ },
+ }),
+ /3 is not a valid value for socksVersion/,
+ "proxy.settings.set rejects with an invalid socksVersion value."
+ );
+
+ browser.test.sendMessage("done");
+ };
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ permissions: ["proxy"],
+ },
+ incognitoOverride: "spanning",
+ });
+
+ await extension.startup();
+ await extension.awaitMessage("done");
+ await extension.unload();
+});
+
+// Verify proxy prefs are unset on permission removal.
+add_task(async function test_proxy_settings_permissions() {
+ // TODO bug 1725981: proxy.settings is not supported on Android.
+ if (AppConstants.platform === "android") {
+ info("proxy.settings not supported on Android; skipping");
+ return;
+ }
+ async function background() {
+ const permObj = { permissions: ["proxy"] };
+ browser.test.onMessage.addListener(async (msg, value) => {
+ if (msg === "request") {
+ browser.test.log("requesting proxy permission");
+ await browser.permissions.request(permObj);
+ browser.test.log("setting proxy values");
+ await browser.proxy.settings.set({ value });
+ browser.test.sendMessage("set");
+ } else if (msg === "remove") {
+ await browser.permissions.remove(permObj);
+ browser.test.sendMessage("removed");
+ }
+ });
+ }
+
+ let prefNames = [
+ "network.proxy.type",
+ "network.proxy.http",
+ "network.proxy.http_port",
+ "network.proxy.ssl",
+ "network.proxy.ssl_port",
+ "network.proxy.socks",
+ "network.proxy.socks_port",
+ "network.proxy.socks_version",
+ "network.proxy.no_proxies_on",
+ ];
+
+ function checkSettings(msg, expectUserValue = false) {
+ info(msg);
+ for (let pref of prefNames) {
+ equal(
+ expectUserValue,
+ Services.prefs.prefHasUserValue(pref),
+ `${pref} set as expected ${Preferences.get(pref)}`
+ );
+ }
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ optional_permissions: ["proxy"],
+ },
+ incognitoOverride: "spanning",
+ useAddonManager: "permanent",
+ });
+ await extension.startup();
+ checkSettings("setting is not set after startup");
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("request", {
+ proxyType: "manual",
+ http: "www.mozilla.org:8080",
+ httpProxyAll: false,
+ ssl: "www.mozilla.org:8082",
+ socks: "mozilla.org:8083",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ });
+ await extension.awaitMessage("set");
+ checkSettings("setting was set after request", true);
+
+ extension.sendMessage("remove");
+ await extension.awaitMessage("removed");
+ checkSettings("setting is reset after remove");
+
+ // Set again to test after restart
+ extension.sendMessage("request", {
+ proxyType: "manual",
+ http: "www.mozilla.org:8080",
+ httpProxyAll: false,
+ ssl: "www.mozilla.org:8082",
+ socks: "mozilla.org:8083",
+ socksVersion: 4,
+ passthrough: ".mozilla.org",
+ });
+ await extension.awaitMessage("set");
+ checkSettings("setting was set after request", true);
+ });
+
+ // force the permissions store to be re-read on startup
+ await ExtensionPermissions._uninit();
+ resetHandlingUserInput();
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitBackgroundStarted();
+
+ await withHandlingUserInput(extension, async () => {
+ extension.sendMessage("remove");
+ await extension.awaitMessage("removed");
+ checkSettings("setting is reset after remove");
+ });
+
+ await extension.unload();
+});