mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
Bug 1482271 - Add preferences UI for the DNS over HTTPS mode and uri prefs r=johannh,flod
MozReview-Commit-ID: G10vRxluGCa Differential Revision: https://phabricator.services.mozilla.com/D4049 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
c6fdfda207
commit
2b03865bc5
@ -33,6 +33,8 @@ Preferences.addAll([
|
||||
{ id: "network.proxy.backup.ssl_port", type: "int" },
|
||||
{ id: "network.proxy.backup.socks", type: "string" },
|
||||
{ id: "network.proxy.backup.socks_port", type: "int" },
|
||||
{ id: "network.trr.mode", type: "int" },
|
||||
{ id: "network.trr.uri", type: "string" },
|
||||
]);
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
@ -277,5 +279,35 @@ var gConnectionsDialog = {
|
||||
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY)
|
||||
.then(setInputsDisabledState);
|
||||
}
|
||||
},
|
||||
|
||||
isDnsOverHttpsEnabled() {
|
||||
// values outside 1:4 are considered falsey/disabled in this context
|
||||
let trrPref = Preferences.get("network.trr.mode");
|
||||
let enabled = trrPref.value > 0 && trrPref.value < 5;
|
||||
return enabled;
|
||||
},
|
||||
|
||||
readDnsOverHttpsMode() {
|
||||
// called to update checked element property to reflect current pref value
|
||||
let enabled = this.isDnsOverHttpsEnabled();
|
||||
let uriPref = Preferences.get("network.trr.uri");
|
||||
uriPref.disabled = !enabled;
|
||||
return enabled;
|
||||
},
|
||||
|
||||
writeDnsOverHttpsMode() {
|
||||
// called to update pref with user change
|
||||
let trrModeCheckbox = document.getElementById("networkDnsOverHttps");
|
||||
// we treat checked/enabled as mode 2
|
||||
return trrModeCheckbox.checked ? 2 : 0;
|
||||
},
|
||||
|
||||
writeDnsOverHttpsUri() {
|
||||
// called to update pref with user input
|
||||
let input = document.getElementById("networkDnsOverHttpsUrl");
|
||||
let uriString = input.value.trim();
|
||||
// turn an empty string into `undefined` to clear the pref back to the default
|
||||
return uriString.length ? uriString : undefined;
|
||||
}
|
||||
};
|
||||
|
@ -148,6 +148,18 @@
|
||||
<checkbox id="networkProxySOCKSRemoteDNS"
|
||||
preference="network.proxy.socks_remote_dns"
|
||||
data-l10n-id="connection-proxy-socks-remote-dns" />
|
||||
<checkbox id="networkDnsOverHttps"
|
||||
data-l10n-id="connection-dns-over-https"
|
||||
preference="network.trr.mode"
|
||||
onsyncfrompreference="return gConnectionsDialog.readDnsOverHttpsMode();"
|
||||
onsynctopreference="return gConnectionsDialog.writeDnsOverHttpsMode()" />
|
||||
<hbox class="indent" flex="1" align="center">
|
||||
<label control="networkDnsOverHttpsUrl" data-l10n-id="connection-dns-over-https-url"
|
||||
data-l10n-attrs="tooltiptext"/>
|
||||
<textbox id="networkDnsOverHttpsUrl" flex="1" preference="network.trr.uri"
|
||||
placeholder="https://doh.example.com/dns-query"
|
||||
onsynctopreference="return gConnectionsDialog.writeDnsOverHttpsUri()" />
|
||||
</hbox>
|
||||
<separator/>
|
||||
</vbox>
|
||||
</dialog>
|
||||
|
@ -652,12 +652,12 @@
|
||||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="network-proxy-title"/>
|
||||
<label class="header-name" flex="1" data-l10n-id="network-settings-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Network Proxy-->
|
||||
<!-- Network Settings-->
|
||||
<groupbox id="connectionGroup" data-category="paneGeneral" hidden="true">
|
||||
<caption class="search-header" hidden="true"><label data-l10n-id="network-proxy-title"/></caption>
|
||||
<caption class="search-header" hidden="true"><label data-l10n-id="network-settings-title"/></caption>
|
||||
|
||||
<hbox align="center">
|
||||
<hbox align="center" flex="1">
|
||||
@ -694,7 +694,9 @@
|
||||
connection-proxy-autotype.label,
|
||||
connection-proxy-reload.label,
|
||||
connection-proxy-autologin.label,
|
||||
connection-proxy-socks-remote-dns.label
|
||||
connection-proxy-socks-remote-dns.label,
|
||||
connection-dns-over-https,
|
||||
connection-dns-over-https-url
|
||||
" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
@ -42,6 +42,7 @@ skip-if = os != "win" # Windows-specific handler application selection dialog
|
||||
[browser_connection_bug388287.js]
|
||||
[browser_connection_bug1445991.js]
|
||||
skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
|
||||
[browser_connection_dnsoverhttps.js]
|
||||
[browser_contentblocking.js]
|
||||
[browser_cookies_exceptions.js]
|
||||
[browser_defaultbrowser_alwayscheck.js]
|
||||
|
@ -0,0 +1,172 @@
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const SUBDIALOG_URL = "chrome://browser/content/preferences/connection.xul";
|
||||
const TRR_MODE_PREF = "network.trr.mode";
|
||||
const TRR_URI_PREF = "network.trr.uri";
|
||||
|
||||
const modeCheckboxSelector = "#networkDnsOverHttps";
|
||||
const uriTextboxSelector = "#networkDnsOverHttpsUrl";
|
||||
const defaultPrefValues = Object.freeze({
|
||||
[TRR_MODE_PREF]: 0,
|
||||
[TRR_URI_PREF]: "",
|
||||
});
|
||||
|
||||
function resetPrefs() {
|
||||
Services.prefs.clearUserPref(TRR_MODE_PREF);
|
||||
Services.prefs.clearUserPref(TRR_URI_PREF);
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
await new Promise(res => {
|
||||
resetPrefs();
|
||||
open_preferences(res);
|
||||
});
|
||||
}
|
||||
|
||||
async function openConnectionsSubDialog() {
|
||||
/*
|
||||
The connection dialog has type="child", So it has to be opened as a sub dialog
|
||||
of the main pref tab. Prefs only get updated after the subdialog is confirmed & closed
|
||||
*/
|
||||
let dialog = await openAndLoadSubDialog(SUBDIALOG_URL);
|
||||
ok(dialog, "connection window opened");
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function waitForPrefObserver(name) {
|
||||
return new Promise(resolve => {
|
||||
const observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aData == name) {
|
||||
Services.prefs.removeObserver(name, observer);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
Services.prefs.addObserver(name, observer);
|
||||
});
|
||||
}
|
||||
|
||||
async function testWithProperties(props) {
|
||||
info("testing with " + JSON.stringify(props));
|
||||
if (props.hasOwnProperty(TRR_MODE_PREF)) {
|
||||
Services.prefs.setIntPref(TRR_MODE_PREF, props[TRR_MODE_PREF]);
|
||||
}
|
||||
if (props.hasOwnProperty(TRR_URI_PREF)) {
|
||||
Services.prefs.setStringPref(TRR_URI_PREF, props[TRR_URI_PREF]);
|
||||
}
|
||||
|
||||
let dialog = await openConnectionsSubDialog();
|
||||
let doc = dialog.document;
|
||||
let dialogClosingPromise = BrowserTestUtils.waitForEvent(doc.documentElement,
|
||||
"dialogclosing");
|
||||
let modeCheckbox = doc.querySelector(modeCheckboxSelector);
|
||||
let uriTextbox = doc.querySelector(uriTextboxSelector);
|
||||
let uriPrefChangedPromise;
|
||||
let modePrefChangedPromise;
|
||||
|
||||
if (props.hasOwnProperty("expectedModeChecked")) {
|
||||
is(modeCheckbox.checked, props.expectedModeChecked, "mode checkbox has expected checked state");
|
||||
}
|
||||
if (props.hasOwnProperty("expectedUriValue")) {
|
||||
is(uriTextbox.value, props.expectedUriValue, "URI textbox has expected value");
|
||||
}
|
||||
if (props.clickMode) {
|
||||
modePrefChangedPromise = waitForPrefObserver(TRR_MODE_PREF);
|
||||
modeCheckbox.scrollIntoView();
|
||||
EventUtils.synthesizeMouseAtCenter(modeCheckbox, {},
|
||||
modeCheckbox.ownerGlobal);
|
||||
}
|
||||
if (props.hasOwnProperty("inputUriKeys")) {
|
||||
uriPrefChangedPromise = waitForPrefObserver(TRR_URI_PREF);
|
||||
uriTextbox.focus();
|
||||
// delete whatever is in there
|
||||
EventUtils.synthesizeKey("a", { accelKey: true }, uriTextbox.ownerGlobal);
|
||||
EventUtils.synthesizeKey("KEY_Backspace", {}, uriTextbox.ownerGlobal);
|
||||
// and type in the new stuff
|
||||
EventUtils.synthesizeKey(props.inputUriKeys, {}, uriTextbox.ownerGlobal);
|
||||
let changePromise = waitForEvent(uriTextbox, "change");
|
||||
// move focus to trigger change event
|
||||
modeCheckbox.focus();
|
||||
await changePromise;
|
||||
}
|
||||
|
||||
doc.documentElement.acceptDialog();
|
||||
|
||||
let dialogClosingEvent = await dialogClosingPromise;
|
||||
ok(dialogClosingEvent, "connection window closed");
|
||||
|
||||
await Promise.all([uriPrefChangedPromise, modePrefChangedPromise]);
|
||||
|
||||
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.hasOwnProperty("expectedModePref")) {
|
||||
let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
|
||||
is(modePref, props.expectedModePref, "mode pref ended up with the expected value");
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(resetPrefs);
|
||||
|
||||
add_task(async function default_values() {
|
||||
let uriPref = Services.prefs.getStringPref(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_MODE_PREF} matches expected default value`);
|
||||
});
|
||||
|
||||
let testVariations = [
|
||||
// verify state with defaults
|
||||
{ expectedModePref: 0, expectedUriValue: "" },
|
||||
|
||||
// verify each of the modes maps to the correct checked state
|
||||
{ [TRR_MODE_PREF]: 0, expectedModeChecked: false },
|
||||
{ [TRR_MODE_PREF]: 1, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 2, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 3, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 4, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 5, expectedModeChecked: false },
|
||||
// verify an out of bounds mode value maps to the correct checked state
|
||||
{ [TRR_MODE_PREF]: 77, expectedModeChecked: false },
|
||||
|
||||
// verify toggling the checkbox gives the right outcomes
|
||||
{ clickMode: true, expectedModeValue: 2, expectedUriValue: "" },
|
||||
{
|
||||
[TRR_MODE_PREF]: 4,
|
||||
expectedModeChecked: true, clickMode: true, expectedModePref: 0,
|
||||
},
|
||||
{
|
||||
[TRR_MODE_PREF]: 2, [TRR_URI_PREF]: "https://example.com",
|
||||
expectedModeValue: true, expectedUriValue: "https://example.com",
|
||||
},
|
||||
{
|
||||
clickMode: true, inputUriKeys: "https://example.com",
|
||||
expectedModePref: 2, expectedFinalUriPref: "https://example.com",
|
||||
},
|
||||
|
||||
// verify the uri can be cleared
|
||||
{
|
||||
[TRR_MODE_PREF]: 2, [TRR_URI_PREF]: "https://example.com",
|
||||
expectedUriValue: "https://example.com", inputUriKeys: "", expectedFinalUriPref: "",
|
||||
},
|
||||
|
||||
// verify uri gets sanitized
|
||||
{
|
||||
clickMode: true, inputUriKeys: " https://example.com ",
|
||||
expectedModePref: 2, expectedFinalUriPref: "https://example.com",
|
||||
},
|
||||
];
|
||||
|
||||
for (let props of testVariations) {
|
||||
add_task(async function() {
|
||||
await setup();
|
||||
await testWithProperties(props);
|
||||
resetPrefs();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
}
|
@ -81,3 +81,11 @@ connection-proxy-autologin =
|
||||
connection-proxy-socks-remote-dns =
|
||||
.label = Proxy DNS when using SOCKS v5
|
||||
.accesskey = D
|
||||
|
||||
connection-dns-over-https =
|
||||
.label = Enable DNS over HTTPS
|
||||
.accesskey = H
|
||||
|
||||
connection-dns-over-https-url = URL
|
||||
.accesskey = U
|
||||
.tooltiptext = URL for resolving DNS over HTTPS
|
||||
|
@ -405,7 +405,7 @@ browsing-search-on-start-typing =
|
||||
|
||||
## General Section - Proxy
|
||||
|
||||
network-proxy-title = Network Proxy
|
||||
network-settings-title = Network Settings
|
||||
|
||||
network-proxy-connection-description = Configure how { -brand-short-name } connects to the internet.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user