Skip to content

Commit 4f485db

Browse files
qml, proxy: Allow IPv6 and move out UI validation
Allowed to configure the proxy with an IPv6 address and moved the validation out from the UI/ control to the node interface.
1 parent c117acc commit 4f485db

File tree

6 files changed

+52
-33
lines changed

6 files changed

+52
-33
lines changed

src/interfaces/node.h

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include <tuple>
2323
#include <vector>
2424

25+
static const char DEFAULT_PROXY_HOST[] = "127.0.0.1";
26+
static constexpr uint16_t DEFAULT_PROXY_PORT = 9050;
27+
2528
class BanMan;
2629
class CFeeRate;
2730
class CNodeStats;
@@ -268,6 +271,8 @@ class Node
268271
//! accessible across processes.
269272
virtual node::NodeContext* context() { return nullptr; }
270273
virtual void setContext(node::NodeContext* context) { }
274+
virtual bool validateProxyAddress(const std::string ipAddress) = 0;
275+
virtual std::string defaultProxyAddress() = 0;
271276
};
272277

273278
//! Return implementation of Node interface.

src/node/interfaces.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <uint256.h>
4646
#include <univalue.h>
4747
#include <util/check.h>
48+
#include <util/strencodings.h>
4849
#include <util/translation.h>
4950
#include <validation.h>
5051
#include <validationinterface.h>
@@ -398,6 +399,21 @@ class NodeImpl : public Node
398399
ArgsManager& args() { return *Assert(Assert(m_context)->args); }
399400
ChainstateManager& chainman() { return *Assert(m_context->chainman); }
400401
NodeContext* m_context{nullptr};
402+
bool validateProxyAddress(const std::string ipAddress) override
403+
{
404+
uint16_t port{0};
405+
std::string hostname;
406+
if (!SplitHostPort(ipAddress, port, hostname) || !port) return false;
407+
408+
CService serv(LookupNumeric(ipAddress, DEFAULT_PROXY_PORT));
409+
410+
Proxy addrProxy = Proxy(serv, true);
411+
return addrProxy.IsValid();
412+
}
413+
std::string defaultProxyAddress() override
414+
{
415+
return std::string(DEFAULT_PROXY_HOST) + ":" + ToString(DEFAULT_PROXY_PORT);
416+
}
401417
};
402418

403419
bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock, const CChain& active, const BlockManager& blockman)

src/qml/components/ProxySettings.qml

+17-6
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.")
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

src/qml/controls/IPAddressValueInput.qml

+1-27
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ 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: RegExpValidator { regExp: /[0-9A-Fa-f.:\[\]]*/ } // Allow only IPv4/ IPv6 chars
2020

2121
maximumLength: 21
2222

@@ -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
}

src/qml/models/nodemodel.cpp

+10
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 ipAddress)
171+
{
172+
return m_node.validateProxyAddress(ipAddress.toStdString());
173+
}
174+
175+
QString NodeModel::defaultProxyAddress()
176+
{
177+
return QString::fromStdString(m_node.defaultProxyAddress());
178+
}

src/qml/models/nodemodel.h

+3
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 ipAddress);
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)