Bug 1713036 - Use Remote Settings config in DoH preferences UI. r=jaws,preferences-reviewers,necko-reviewers,valentin

Depends on D116798

Differential Revision: https://phabricator.services.mozilla.com/D117960
This commit is contained in:
Nihanth Subramanya 2021-06-23 23:28:16 +00:00
parent a5d79d29ab
commit e78d4b3565
10 changed files with 114 additions and 87 deletions

View File

@ -7,6 +7,12 @@
/* import-globals-from ../../../../toolkit/content/preferencesBindings.js */
/* import-globals-from ../extensionControlled.js */
ChromeUtils.defineModuleGetter(
this,
"DoHConfigController",
"resource:///modules/DoHConfig.jsm"
);
document
.getElementById("ConnectionsDialog")
.addEventListener("dialoghelp", window.top.openPrefsHelp);
@ -33,13 +39,16 @@ Preferences.addAll([
{ id: "network.proxy.backup.ssl_port", type: "int" },
{ id: "network.trr.mode", type: "int" },
{ id: "network.trr.uri", type: "string" },
{ id: "network.trr.resolvers", type: "string" },
{ id: "network.trr.custom_uri", type: "string" },
{ id: "doh-rollout.enabled", type: "bool" },
{ id: "doh-rollout.disable-heuristics", type: "bool" },
{ id: "doh-rollout.skipHeuristicsCheck", type: "bool" },
]);
const DoHConfigObserver = () => {
gConnectionsDialog.initDnsOverHttpsUI();
};
window.addEventListener(
"DOMContentLoaded",
() => {
@ -56,9 +65,20 @@ window.addEventListener(
gConnectionsDialog.updateDnsOverHttpsUI();
});
Preferences.get("network.trr.resolvers").on("change", () => {
gConnectionsDialog.initDnsOverHttpsUI();
});
Services.obs.addObserver(
DoHConfigObserver,
DoHConfigController.kConfigUpdateTopic
);
window.addEventListener(
"unload",
e => {
Services.obs.removeObserver(
DoHConfigObserver,
DoHConfigController.kConfigUpdateTopic
);
},
{ once: true }
);
// XXX: We can't init the DNS-over-HTTPs UI until the onsyncfrompreference for network.trr.mode
// has been called. The uiReady promise will be resolved after the first call to
@ -107,9 +127,12 @@ var gConnectionsDialog = {
if (customValue) {
Services.prefs.setStringPref("network.trr.uri", customValue);
} else {
Services.prefs.clearUserPref("network.trr.uri");
Services.prefs.setStringPref(
"network.trr.uri",
DoHConfigController.currentConfig.fallbackProviderURI
);
}
} else {
} else if (this.isDnsOverHttpsEnabled()) {
Services.prefs.setStringPref(
"network.trr.uri",
dnsOverHttpsResolverChoice
@ -399,30 +422,14 @@ var gConnectionsDialog = {
},
get dnsOverHttpsResolvers() {
let rawValue = Preferences.get("network.trr.resolvers", "").value;
let providers = DoHConfigController.currentConfig.providerList;
// if there's no default, we'll hold its position with an empty string
let defaultURI = Preferences.get("network.trr.uri", "").defaultValue;
let providers = [];
if (rawValue) {
try {
providers = JSON.parse(rawValue);
} catch (ex) {
Cu.reportError(
`Bad JSON data in pref network.trr.resolvers: ${rawValue}`
);
}
}
if (!Array.isArray(providers)) {
Cu.reportError(
`Expected a JSON array in network.trr.resolvers: ${rawValue}`
);
providers = [];
}
let defaultIndex = providers.findIndex(p => p.url == defaultURI);
let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI;
let defaultIndex = providers.findIndex(p => p.uri == defaultURI);
if (defaultIndex == -1 && defaultURI) {
// the default value for the pref isn't included in the resolvers list
// so we'll make a stub for it. Without an id, we'll have to use the url as the label
providers.unshift({ url: defaultURI });
providers.unshift({ uri: defaultURI });
}
return providers;
},
@ -491,7 +498,7 @@ var gConnectionsDialog = {
if (
currentURI &&
!customURI &&
!resolvers.find(r => r.url == currentURI)
!resolvers.find(r => r.uri == currentURI)
) {
Services.prefs.setStringPref("network.trr.custom_uri", currentURI);
}
@ -536,24 +543,24 @@ var gConnectionsDialog = {
initDnsOverHttpsUI() {
let resolvers = this.dnsOverHttpsResolvers;
let defaultURI = Preferences.get("network.trr.uri").defaultValue;
let defaultURI = DoHConfigController.currentConfig.fallbackProviderURI;
let currentURI = Preferences.get("network.trr.uri").value;
let menu = document.getElementById("networkDnsOverHttpsResolverChoices");
// populate the DNS-Over-HTTPs resolver list
menu.removeAllItems();
for (let resolver of resolvers) {
let item = menu.appendItem(undefined, resolver.url);
if (resolver.url == defaultURI) {
let item = menu.appendItem(undefined, resolver.uri);
if (resolver.uri == defaultURI) {
document.l10n.setAttributes(
item,
"connection-dns-over-https-url-item-default",
{
name: resolver.name || resolver.url,
name: resolver.UIName || resolver.uri,
}
);
} else {
item.label = resolver.name || resolver.url;
item.label = resolver.UIName || resolver.uri;
}
}
let lastItem = menu.appendItem(undefined, "custom");
@ -564,7 +571,7 @@ var gConnectionsDialog = {
// set initial selection in the resolver provider picker
let selectedIndex = currentURI
? resolvers.findIndex(r => r.url == currentURI)
? resolvers.findIndex(r => r.uri == currentURI)
: 0;
if (selectedIndex == -1) {
// select the last "Custom" item

View File

@ -1,3 +1,10 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
requestLongerTimeout(2);
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
@ -5,29 +12,34 @@ ChromeUtils.defineModuleGetter(
"DoHController",
"resource:///modules/DoHController.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"DoHConfigController",
"resource:///modules/DoHConfig.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"DoHTestUtils",
"resource://testing-common/DoHTestUtils.jsm"
);
const SUBDIALOG_URL =
"chrome://browser/content/preferences/dialogs/connection.xhtml";
const TRR_MODE_PREF = "network.trr.mode";
const TRR_URI_PREF = "network.trr.uri";
const TRR_RESOLVERS_PREF = "network.trr.resolvers";
const TRR_CUSTOM_URI_PREF = "network.trr.custom_uri";
const ROLLOUT_ENABLED_PREF = "doh-rollout.enabled";
const ROLLOUT_SELF_ENABLED_PREF = "doh-rollout.self-enabled";
const HEURISTICS_DISABLED_PREF = "doh-rollout.disable-heuristics";
const DEFAULT_RESOLVER_VALUE = "https://mozilla.cloudflare-dns.com/dns-query";
const NEXTDNS_RESOLVER_VALUE = "https://firefox.dns.nextdns.io/";
const FIRST_RESOLVER_VALUE = DoHTestUtils.providers[0].uri;
const SECOND_RESOLVER_VALUE = DoHTestUtils.providers[1].uri;
const DEFAULT_RESOLVER_VALUE = FIRST_RESOLVER_VALUE;
const modeCheckboxSelector = "#networkDnsOverHttps";
const uriTextboxSelector = "#networkCustomDnsOverHttpsInput";
const resolverMenulistSelector = "#networkDnsOverHttpsResolverChoices";
const defaultPrefValues = Object.freeze({
[TRR_MODE_PREF]: 0,
[TRR_URI_PREF]: "https://mozilla.cloudflare-dns.com/dns-query",
[TRR_RESOLVERS_PREF]: JSON.stringify([
{ name: "Cloudflare", url: DEFAULT_RESOLVER_VALUE },
{ name: "example.org", url: "https://example.org/dns-query" },
]),
[TRR_CUSTOM_URI_PREF]: "",
});
@ -35,7 +47,6 @@ async function resetPrefs() {
await DoHController._uninit();
Services.prefs.clearUserPref(TRR_MODE_PREF);
Services.prefs.clearUserPref(TRR_URI_PREF);
Services.prefs.clearUserPref(TRR_RESOLVERS_PREF);
Services.prefs.clearUserPref(TRR_CUSTOM_URI_PREF);
Services.prefs.getChildList("doh-rollout.").forEach(pref => {
Services.prefs.clearUserPref(pref);
@ -44,12 +55,13 @@ async function resetPrefs() {
// confuse tests running after this one that are looking at those.
Services.telemetry.clearEvents();
await DoHController.init();
await DoHTestUtils.resetRemoteSettingsConfig();
}
Services.prefs.setStringPref("network.trr.confirmationNS", "skip");
let preferencesOpen = new Promise(res => open_preferences(res));
registerCleanupFunction(() => {
resetPrefs();
registerCleanupFunction(async () => {
await resetPrefs();
gBrowser.removeCurrentTab();
Services.prefs.clearUserPref("network.trr.confirmationNS");
});
@ -122,10 +134,6 @@ async function testWithProperties(props, startTime) {
if (props.hasOwnProperty(TRR_URI_PREF)) {
Services.prefs.setStringPref(TRR_URI_PREF, props[TRR_URI_PREF]);
}
if (props.hasOwnProperty(TRR_RESOLVERS_PREF)) {
info(`Setting ${TRR_RESOLVERS_PREF} to ${props[TRR_RESOLVERS_PREF]}`);
Services.prefs.setStringPref(TRR_RESOLVERS_PREF, props[TRR_RESOLVERS_PREF]);
}
let dialog = await openConnectionsSubDialog();
await dialog.uiReady;
@ -263,12 +271,19 @@ async function testWithProperties(props, startTime) {
info(Date.now() - startTime + ": testWithProperties: prefs changed");
if (props.hasOwnProperty("expectedFinalUriPref")) {
let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
is(
uriPref,
props.expectedFinalUriPref,
"uri pref ended up with the expected value"
);
if (props.expectedFinalUriPref) {
let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
is(
uriPref,
props.expectedFinalUriPref,
"uri pref ended up with the expected value"
);
} else {
ok(
!Services.prefs.prefHasUserValue(TRR_URI_PREF),
"uri pref ended up with the expected value (unset)"
);
}
}
if (props.hasOwnProperty("expectedModePref")) {
@ -305,17 +320,16 @@ async function testWithProperties(props, startTime) {
add_task(async function default_values() {
let customUriPref = Services.prefs.getStringPref(TRR_CUSTOM_URI_PREF);
let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
let uriPrefHasUserValue = Services.prefs.prefHasUserValue(TRR_URI_PREF);
let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
is(
modePref,
defaultPrefValues[TRR_MODE_PREF],
`Actual value of ${TRR_MODE_PREF} matches expected default value`
);
is(
uriPref,
defaultPrefValues[TRR_URI_PREF],
`Actual value of ${TRR_URI_PREF} matches expected default value`
ok(
!uriPrefHasUserValue,
`Actual value of ${TRR_URI_PREF} matches expected default value (unset)`
);
is(
customUriPref,
@ -334,7 +348,6 @@ let testVariations = [
name: "mode 1",
[TRR_MODE_PREF]: 1,
expectedModeChecked: false,
expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
},
{
name: "mode 2",
@ -352,7 +365,6 @@ let testVariations = [
name: "mode 4",
[TRR_MODE_PREF]: 4,
expectedModeChecked: false,
expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
},
{ name: "mode 5", [TRR_MODE_PREF]: 5, expectedModeChecked: false },
// verify an out of bounds mode value maps to the correct checked state
@ -416,14 +428,14 @@ let testVariations = [
{
name: "Select NextDNS as TRR provider",
[TRR_MODE_PREF]: 2,
selectResolver: NEXTDNS_RESOLVER_VALUE,
expectedFinalUriPref: NEXTDNS_RESOLVER_VALUE,
selectResolver: SECOND_RESOLVER_VALUE,
expectedFinalUriPref: SECOND_RESOLVER_VALUE,
},
{
name: "return to default from NextDNS",
[TRR_MODE_PREF]: 2,
[TRR_URI_PREF]: NEXTDNS_RESOLVER_VALUE,
expectedResolverListValue: NEXTDNS_RESOLVER_VALUE,
[TRR_URI_PREF]: SECOND_RESOLVER_VALUE,
expectedResolverListValue: SECOND_RESOLVER_VALUE,
selectResolver: DEFAULT_RESOLVER_VALUE,
expectedFinalUriPref: DEFAULT_RESOLVER_VALUE,
},
@ -474,11 +486,9 @@ let testVariations = [
},
{
name: "empty default resolver list",
[TRR_RESOLVERS_PREF]: "",
[TRR_MODE_PREF]: 2,
[TRR_URI_PREF]: "https://example.com",
[TRR_CUSTOM_URI_PREF]: "",
[TRR_RESOLVERS_PREF]: "",
expectedUriValue: "https://example.com",
expectedResolverListValue: "custom",
expectedFinalUriPref: "https://example.com",

View File

@ -9414,6 +9414,12 @@
value: 1048576
mirror: always
# Default global TRR provider
- name: network.trr.default_provider_uri
type: String
value: "https://mozilla.cloudflare-dns.com/dns-query"
mirror: never
# Single TRR request timeout, in milliseconds
- name: network.trr.request_timeout_ms
type: RelaxedAtomicUint32

View File

@ -3926,11 +3926,7 @@ pref("network.connectivity-service.IPv6.url", "http://detectportal.firefox.com/s
// DNS Trusted Recursive Resolver
// 0 - default off, 1 - reserved/off, 2 - TRR first, 3 - TRR only, 4 - reserved/off, 5 off by choice
pref("network.trr.mode", 0);
// DNS-over-HTTP service to use, must be HTTPS://
pref("network.trr.uri", "https://mozilla.cloudflare-dns.com/dns-query");
// List of DNS-over-HTTP resolver service providers. This pref populates the
// drop-down list in the Network Settings dialog box in about:preferences.
pref("network.trr.resolvers", "[{ \"name\": \"Cloudflare\", \"url\": \"https://mozilla.cloudflare-dns.com/dns-query\" },{ \"name\": \"NextDNS\", \"url\": \"https://firefox.dns.nextdns.io/\" }]");
pref("network.trr.uri", "");
// credentials to pass to DOH end-point
pref("network.trr.credentials", "");
pref("network.trr.custom_uri", "");

View File

@ -372,6 +372,7 @@ nsresult TRRService::ReadPrefs(const char* name) {
}
}
if (!name || !strcmp(name, TRR_PREF("uri")) ||
!strcmp(name, TRR_PREF("default_provider_uri")) ||
!strcmp(name, kRolloutURIPref)) {
OnTRRURIChange();
}

View File

@ -13,6 +13,7 @@
#include "nsIDNSService.h"
// Put DNSLogging.h at the end to avoid LOG being overwritten by other headers.
#include "DNSLogging.h"
#include "mozilla/StaticPrefs_network.h"
namespace mozilla {
namespace net {
@ -85,7 +86,7 @@ void TRRServiceBase::CheckURIPrefs() {
}
// Otherwise just use the default value.
MaybeSetPrivateURI(mURIPref);
MaybeSetPrivateURI(mDefaultURIPref);
}
// static
@ -144,6 +145,7 @@ void TRRServiceBase::OnTRRURIChange() {
mURIPrefHasUserValue = Preferences::HasUserValue("network.trr.uri");
Preferences::GetCString("network.trr.uri", mURIPref);
Preferences::GetCString(kRolloutURIPref, mRolloutURIPref);
Preferences::GetCString("network.trr.default_provider_uri", mDefaultURIPref);
CheckURIPrefs();
}

View File

@ -44,6 +44,7 @@ class TRRServiceBase {
bool mURIPrefHasUserValue = false;
nsCString mURIPref;
nsCString mRolloutURIPref;
nsCString mDefaultURIPref;
Atomic<nsIDNSService::ResolverMode, Relaxed> mMode;
Atomic<bool, Relaxed> mURISetByDetection;

View File

@ -23,8 +23,9 @@ namespace mozilla {
namespace net {
static const char* gTRRUriCallbackPrefs[] = {
"network.trr.uri", "network.trr.mode", kRolloutURIPref, kRolloutModePref,
nullptr,
"network.trr.uri", "network.trr.default_provider_uri",
"network.trr.mode", kRolloutURIPref,
kRolloutModePref, nullptr,
};
NS_IMPL_ISUPPORTS(TRRServiceParent, nsIObserver, nsISupportsWeakReference)
@ -133,6 +134,7 @@ void TRRServiceParent::PrefsChanged(const char* aName, void* aSelf) {
void TRRServiceParent::prefsChanged(const char* aName) {
if (!aName || !strcmp(aName, "network.trr.uri") ||
!strcmp(aName, "network.trr.default_provider_uri") ||
!strcmp(aName, kRolloutURIPref)) {
OnTRRURIChange();
}

View File

@ -534,9 +534,9 @@ add_task(async function test_detected_uri() {
dns.clearCache(true);
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.clearUserPref("network.trr.uri");
let defaultURI = gDefaultPref.getCharPref("network.trr.uri");
let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri");
gDefaultPref.setCharPref(
"network.trr.uri",
"network.trr.default_provider_uri",
`https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6`
);
await new TRRDNSListener("domainA.example.org.", "3.4.5.6");
@ -544,7 +544,7 @@ add_task(async function test_detected_uri() {
`https://foo.example.com:${h2Port}/doh?responseIP=1.2.3.4`
);
await new TRRDNSListener("domainB.example.org.", "1.2.3.4");
gDefaultPref.setCharPref("network.trr.uri", defaultURI);
gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
// With a user-set doh uri this time.
dns.clearCache(true);
@ -562,7 +562,7 @@ add_task(async function test_detected_uri() {
Services.prefs.setIntPref("network.trr.mode", 3);
Services.prefs.clearUserPref("network.trr.uri");
gDefaultPref.setCharPref(
"network.trr.uri",
"network.trr.default_provider_uri",
`https://foo.example.com:${h2Port}/doh?responseIP=3.4.5.6`
);
await new TRRDNSListener("domainA.example.org.", "3.4.5.6");
@ -584,15 +584,15 @@ add_task(async function test_detected_uri() {
await new TRRDNSListener("domainC.example.org.", "3.4.5.6");
gDefaultPref.setCharPref("network.trr.uri", defaultURI);
gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
});
add_task(async function test_pref_changes() {
info("Testing pref change handling");
Services.prefs.clearUserPref("network.trr.uri");
let defaultURI = gDefaultPref.getCharPref("network.trr.uri");
let defaultURI = gDefaultPref.getCharPref("network.trr.default_provider_uri");
async function doThenCheckURI(closure, expectedURI, expectChange = false) {
async function doThenCheckURI(closure, expectedURI, expectChange = true) {
let uriChanged;
if (expectChange) {
uriChanged = topicObserved("network:trr-uri-changed");
@ -607,7 +607,7 @@ add_task(async function test_pref_changes() {
// setting the default value of the pref should be reflected in the URI
await doThenCheckURI(() => {
gDefaultPref.setCharPref(
"network.trr.uri",
"network.trr.default_provider_uri",
`https://foo.example.com:${h2Port}/doh?default`
);
}, `https://foo.example.com:${h2Port}/doh?default`);
@ -690,7 +690,7 @@ add_task(async function test_pref_changes() {
);
// Restore the pref
gDefaultPref.setCharPref("network.trr.uri", defaultURI);
gDefaultPref.setCharPref("network.trr.default_provider_uri", defaultURI);
});
add_task(async function test_dohrollout_mode() {

View File

@ -371,9 +371,11 @@ add_task(async function test_uri_pref_change() {
add_task(async function test_autodetected_uri() {
const defaultPrefBranch = Services.prefs.getDefaultBranch("");
let defaultURI = defaultPrefBranch.getCharPref("network.trr.uri");
let defaultURI = defaultPrefBranch.getCharPref(
"network.trr.default_provider_uri"
);
defaultPrefBranch.setCharPref(
"network.trr.uri",
"network.trr.default_provider_uri",
`https://foo.example.com:${trrServer.port}/dns-query?changed`
);
// For setDetectedTrrURI to work we must pretend we are using the default.
@ -394,5 +396,5 @@ add_task(async function test_autodetected_uri() {
);
// reset the default URI
defaultPrefBranch.setCharPref("network.trr.uri", defaultURI);
defaultPrefBranch.setCharPref("network.trr.default_provider_uri", defaultURI);
});