Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* -*- 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.socks5_remote_dns": true,
"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: true,
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,
"network.proxy.socks5_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,
"network.proxy.socks5_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.proxy.socks5_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",
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",
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,
proxyDNS: false,
passthrough: ".mozilla.org",
respectBeConservative: true,
}
);
await testProxy(
{
proxyType: "manual",
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,
proxyDNS: false,
passthrough: ".mozilla.org",
respectBeConservative: false,
}
);
await testProxy(
{
proxyType: "manual",
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,
proxyDNS: false,
passthrough: ".mozilla.org",
respectBeConservative: true,
}
);
await testProxy(
{
proxyType: "manual",
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,
proxyDNS: false,
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();
});
add_task(async function test_proxy_socks_remote_dns() {
// 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() {
browser.test.onMessage.addListener(async msg => {
if (msg === "get-proxy-settings") {
let proxySettings = await browser.proxy.settings.get({});
browser.test.sendMessage("return-proxy-settings", proxySettings.value);
}
});
}
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {
permissions: ["proxy"],
},
incognitoOverride: "spanning",
useAddonManager: "temporary",
});
await extension.startup();
registerCleanupFunction(() => {
// Reset the prefs.
Preferences.reset("network.proxy.socks_version");
Preferences.reset("network.proxy.socks_remote_dns");
Preferences.reset("network.proxy.socks5_remote_dns");
});
async function check_proxy_setting(
socksVersion,
socks4RemoteDNS,
socks5RemoteDNS,
expectedProxyDNS
) {
Preferences.set("network.proxy.socks_version", socksVersion);
Preferences.set("network.proxy.socks_remote_dns", socks4RemoteDNS);
Preferences.set("network.proxy.socks5_remote_dns", socks5RemoteDNS);
extension.sendMessage("get-proxy-settings");
let settings = await extension.awaitMessage("return-proxy-settings");
Assert.equal(
expectedProxyDNS,
settings.proxyDNS,
`SOCKS${socksVersion}: remote4: ${socks4RemoteDNS}, remote5: ${socks5RemoteDNS}.`
);
}
// run tests
await check_proxy_setting(
Ci.nsIProxyInfo.SOCKS_V4, // socksVersion
true, // socks4RemoteDNS
false, // socks5RemoteDNS
true // expectedProxyDNS
);
await check_proxy_setting(
Ci.nsIProxyInfo.SOCKS_V5, // socksVersion
true, // socks4RemoteDNS
false, // socks5RemoteDNS
false // expectedProxyDNS
);
await check_proxy_setting(
Ci.nsIProxyInfo.SOCKS_V4, // socksVersion
false, // socks4RemoteDNS
true, // socks5RemoteDNS
false // expectedProxyDNS
);
await check_proxy_setting(
Ci.nsIProxyInfo.SOCKS_V5, // socksVersion
false, // socks4RemoteDNS
true, // socks5RemoteDNS
true // expectedProxyDNS
);
await extension.unload();
});