Skip to content

Commit 69be980

Browse files
committed
Merge #430: Allow IPv6 in Proxy settings and moving validation out from the UI into the model/ interface
7bd7d1c qml, proxy: Allow IPv6 and move out UI validation (pablomartin4btc) Pull request description: The main purposes of this PR are: - Allow configure proxy server with IPv6 (after testing exhaustively in current `bitcoin-qt` [repo](https://github.com/bitcoin-core/gui/) and `bitcoind` - e.g. [IPv6 on Qt](bitcoin-core/gui#836 (comment)); [IP validation in Qt](bitcoin-core/gui#813)) - More importantly: moving the validation logic out from the UI (component/ control/ widget) into the back-end (model/ interfaces). It seemed currently in [Qt](https://github.com/bitcoin-core/gui/) all this logic (validation, network classes) was coupled to the UI since the beginning (more than [12y ago](https://github.com/bitcoin-core/gui/blame/c4443c2be141e5f45bb10376056f3083e97cde50/src/qt/optionsmodel.cpp)) instead of using interfaces (introduced much later) that would be the correct thing to do. Feedback and suggestions are very welcome and will help establish a foundation for leaving business logic out of the UI going forward. --- <details> <summary>In order to test it, if it's the first time you run <code>./src/qt/bitcoin-qt</code> you need to go thru the on-boarding flow (<i>start->next->next->next->next->connection settings->Proxy settings</i>) otherwise you need to go to the settings (top right gear icon) then <i>Connection->Proxy settings</i>.</summary> ![image](https://github.com/user-attachments/assets/9f10c4b7-b7e4-4807-b895-1c03d9c00037) </details> Before this change, only IPv4 address were allow in the value input, now also IPv6 can be entered. --- There are some [look and feel kind of issues](#430 (comment)) that will be handled on follow-ups (issues: #437 and #438). ACKs for top commit: D33r-Gee: tACK [7bd7d1c](7bd7d1c) on Ubuntu 20.04 works as expected. vasild: ACK 7bd7d1c johnny9: ACK 7bd7d1c Tree-SHA512: f633f5729f4ca2a8433560b15722bccd5938bfa55643cd3d925b75ed01006dbc7a56fe3a20766a6bb9e2bb601c8a3828c177de3cccc7728959eb48987838e90c
2 parents 410884d + 7bd7d1c commit 69be980

File tree

4 files changed

+32
-34
lines changed

4 files changed

+32
-34
lines changed

qml/components/ProxySettings.qml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@ import QtQuick.Controls 2.15
77
import QtQuick.Layouts 1.15
88
import "../controls"
99

10+
import org.bitcoincore.qt 1.0
11+
1012
ColumnLayout {
13+
property string ipAndPortHeader: qsTr("IP and Port")
14+
property string invalidIpError: qsTr("Invalid IP address or port format. Use '255.255.255.255:65535' or '[ffff::]:65535'")
15+
1116
spacing: 4
1217
Header {
1318
headerBold: true
@@ -41,14 +46,17 @@ ColumnLayout {
4146
Setting {
4247
id: defaultProxy
4348
Layout.fillWidth: true
44-
header: qsTr("IP and Port")
45-
errorText: qsTr("Invalid IP address or port format. Please use the format '255.255.255.255:65535'.")
49+
header: ipAndPortHeader
50+
errorText: invalidIpError
4651
state: !defaultProxyEnable.loadedItem.checked ? "DISABLED" : "FILLED"
4752
showErrorText: !defaultProxy.loadedItem.validInput && defaultProxyEnable.loadedItem.checked
4853
actionItem: IPAddressValueInput {
4954
parentState: defaultProxy.state
50-
description: "127.0.0.1:9050"
55+
description: nodeModel.defaultProxyAddress()
5156
activeFocusOnTab: true
57+
onTextChanged: {
58+
validInput = nodeModel.validateProxyAddress(text);
59+
}
5260
}
5361
onClicked: {
5462
loadedItem.filled = true
@@ -89,14 +97,17 @@ ColumnLayout {
8997
Setting {
9098
id: torProxy
9199
Layout.fillWidth: true
92-
header: qsTr("IP and Port")
93-
errorText: qsTr("Invalid IP address or port format. Please use the format '255.255.255.255:65535'.")
100+
header: ipAndPortHeader
101+
errorText: invalidIpError
94102
state: !torProxyEnable.loadedItem.checked ? "DISABLED" : "FILLED"
95103
showErrorText: !torProxy.loadedItem.validInput && torProxyEnable.loadedItem.checked
96104
actionItem: IPAddressValueInput {
97105
parentState: torProxy.state
98-
description: "127.0.0.1:9050"
106+
description: nodeModel.defaultProxyAddress()
99107
activeFocusOnTab: true
108+
onTextChanged: {
109+
validInput = nodeModel.validateProxyAddress(text);
110+
}
100111
}
101112
onClicked: {
102113
loadedItem.filled = true

qml/controls/IPAddressValueInput.qml

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ TextInput {
1616
property bool validInput: true
1717
enabled: true
1818
state: root.parentState
19-
validator: RegExpValidator { regExp: /[0-9.:]*/ } // Allow only digits, dots, and colons
19+
validator: RegularExpressionValidator { regularExpression: /^[\][0-9a-f.:]+$/i } // Allow only IPv4/ IPv6 chars
2020

21-
maximumLength: 21
21+
maximumLength: 47
2222

2323
states: [
2424
State {
@@ -53,30 +53,4 @@ TextInput {
5353
Behavior on color {
5454
ColorAnimation { duration: 150 }
5555
}
56-
57-
function isValidIPPort(input)
58-
{
59-
var parts = input.split(":");
60-
if (parts.length !== 2) return false;
61-
if (parts[1].length === 0) return false; // port part is empty
62-
var ipAddress = parts[0];
63-
var ipAddressParts = ipAddress.split(".");
64-
if (ipAddressParts.length !== 4) return false;
65-
for (var i = 0; (i < ipAddressParts.length); i++) {
66-
if (ipAddressParts[i].length === 0) return false; // ip group number part is empty
67-
if (parseInt(ipAddressParts[i]) > 255) return false;
68-
}
69-
var port = parseInt(parts[1]);
70-
if (port < 1 || port > 65535) return false;
71-
return true;
72-
}
73-
74-
// Connections element to ensure validation on editing finished
75-
Connections {
76-
target: root
77-
function onTextChanged() {
78-
// Validate the input whenever editing is finished
79-
validInput = isValidIPPort(root.text);
80-
}
81-
}
8256
}

qml/models/nodemodel.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,13 @@ void NodeModel::ConnectToNumConnectionsChangedSignal()
166166
setNumOutboundPeers(new_num_peers.outbound_full_relay + new_num_peers.block_relay);
167167
});
168168
}
169+
170+
bool NodeModel::validateProxyAddress(QString address_port)
171+
{
172+
return m_node.validateProxyAddress(address_port.toStdString());
173+
}
174+
175+
QString NodeModel::defaultProxyAddress()
176+
{
177+
return QString::fromStdString(m_node.defaultProxyAddress());
178+
}

qml/models/nodemodel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class NodeModel : public QObject
6262
void startShutdownPolling();
6363
void stopShutdownPolling();
6464

65+
Q_INVOKABLE bool validateProxyAddress(QString addr_port);
66+
Q_INVOKABLE QString defaultProxyAddress();
67+
6568
public Q_SLOTS:
6669
void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info);
6770

0 commit comments

Comments
 (0)