1
0

Merge pull request #10441 from f321x/fix_10437

Wizard/qt/qml: validate server address input, fix #10437
This commit is contained in:
ghost43
2026-02-03 17:09:18 +00:00
committed by GitHub
8 changed files with 68 additions and 17 deletions

View File

@@ -39,6 +39,7 @@ ElDialog {
FlatButton {
Layout.fillWidth: true
text: qsTr('Ok')
enabled: serverconfig.addressValid
icon.source: '../../icons/confirmed.png'
onClicked: {
let auto_connect = serverconfig.serverConnectMode == ServerConnectModeComboBox.Mode.Autoconnect

View File

@@ -12,6 +12,7 @@ Item {
property bool showAutoselectServer: true
property alias address: address_tf.text
property alias serverConnectMode: server_connect_mode_cb.currentValue
property alias addressValid: address_tf.valid
implicitHeight: rootLayout.height
@@ -28,6 +29,11 @@ Item {
ServerConnectModeComboBox {
id: server_connect_mode_cb
onCurrentValueChanged: {
if (currentValue == ServerConnectModeComboBox.Mode.Autoconnect) {
address_tf.text = ""
}
}
}
Item {
@@ -63,6 +69,26 @@ Item {
enabled: server_connect_mode_cb.currentValue != ServerConnectModeComboBox.Mode.Autoconnect
width: parent.width
inputMethodHints: Qt.ImhNoPredictiveText
property bool valid: true
function validate() {
if (!enabled) {
valid = true
return
}
valid = Network.isValidServerAddress(address_tf.text)
}
onTextChanged: validate()
onEnabledChanged: validate()
Rectangle {
anchors.fill: parent
color: "red"
opacity: 0.2
visible: !parent.valid
}
}
}

View File

@@ -5,7 +5,7 @@ import QtQuick.Controls
import "../controls"
WizardComponent {
valid: true
valid: sc.addressValid
last: true
title: qsTr('Server')

View File

@@ -206,6 +206,10 @@ class QENetwork(QObject, QtEventListener):
def server(self):
return self._server
@pyqtSlot(str, result=bool)
def isValidServerAddress(self, server: str) -> bool:
return ServerAddr.from_str_with_inference(server) is not None
@pyqtSlot(str, bool, bool)
def setServerParameters(self, server_str: str, auto_connect: bool, one_server: bool):
net_params = self.network.get_parameters()

View File

@@ -361,6 +361,8 @@ class ServerWidget(QWidget, QtEventListener):
ConnectMode.ONESERVER: messages.MSG_CONNECTMODE_ONESERVER,
}
server_e_valid = pyqtSignal(bool)
def __init__(self, network: Network, parent=None):
super().__init__(parent)
self.network = network
@@ -390,6 +392,7 @@ class ServerWidget(QWidget, QtEventListener):
grid.addWidget(self.connect_combo, 0, 1, 1, 3)
self.server_e = QLineEdit()
self.server_e.textChanged.connect(self.validate_server_e)
self.server_e.editingFinished.connect(self.on_server_settings_changed)
grid.addWidget(QLabel(_('Server') + ':'), 1, 0)
grid.addWidget(self.server_e, 1, 1, 1, 3)
@@ -502,6 +505,7 @@ class ServerWidget(QWidget, QtEventListener):
self.status_label_header, self.status_label, self.status_label_helpbutton,
self.height_label_header, self.height_label, self.height_label_helpbutton]:
item.setVisible(self.network._was_started)
self.validate_server_e()
msg = _('Fork detection disabled') if self.is_one_server() else ''
if self.network._was_started:
# Network was started, so we don't run in initial setup wizard.
@@ -522,6 +526,15 @@ class ServerWidget(QWidget, QtEventListener):
msg += _('Your server is on branch {0} ({1} blocks)').format(name, chain.get_branch_size())
self.split_label.setText(msg)
def validate_server_e(self):
if not self.server_e.isEnabled():
self.server_e.setStyleSheet("")
self.server_e_valid.emit(True)
return
server = ServerAddr.from_str_with_inference(self.server_e.text())
self.server_e.setStyleSheet("background-color: rgba(255, 0, 0, 0.2);" if not server else "")
self.server_e_valid.emit(server is not None)
def update_from_config(self):
auto_connect = self.config.NETWORK_AUTO_CONNECT
one_server = self.config.NETWORK_ONESERVER

View File

@@ -91,7 +91,10 @@ class WCServerConfig(WizardComponent):
WizardComponent.__init__(self, parent, wizard, title=_('Server'))
self.sw = ServerWidget(wizard._daemon.network, self)
self.layout().addWidget(self.sw)
self._valid = True
self.sw.server_e_valid.connect(self.on_server_e_valid)
def on_server_e_valid(self, valid):
self.valid = valid
def apply(self):
self.wizard_data['autoconnect'] = self.sw.server_e.text().strip() == ''

View File

@@ -826,7 +826,7 @@ class ServerConnectWizard(AbstractWizard):
self.navmap = {
'welcome': {
'next': lambda d: 'proxy_config' if d['want_proxy'] else 'server_config',
'accept': self.do_configure_autoconnect,
'accept': lambda d: self.do_enable_autoconnect(d) if d['autoconnect'] else None,
'last': lambda d: bool(d['autoconnect'] and not d['want_proxy'])
},
'proxy_config': {
@@ -855,23 +855,27 @@ class ServerConnectWizard(AbstractWizard):
def do_configure_server(self, wizard_data: dict):
self._logger.debug(f'configuring server: {wizard_data!r}')
net_params = self._daemon.network.get_parameters()
server = ''
server = None
oneserver = wizard_data.get('one_server', False)
if not wizard_data['autoconnect']:
try:
server = ServerAddr.from_str_with_inference(wizard_data['server'])
if not server:
raise Exception('failed to parse server %s' % wizard_data['server'])
except Exception:
return
net_params = net_params._replace(server=server, auto_connect=wizard_data['autoconnect'], oneserver=oneserver)
server = ServerAddr.from_str_with_inference(wizard_data.get('server', ''))
if not server:
self._logger.warn('failed to parse server %s' % wizard_data.get('server', ''))
return # Network._start() will set autoconnect and default server
net_params = net_params._replace(
server=server or net_params.server,
auto_connect=wizard_data['autoconnect'],
oneserver=oneserver,
)
self._daemon.network.run_from_another_thread(self._daemon.network.set_parameters(net_params))
def do_configure_autoconnect(self, wizard_data: dict):
self._logger.debug(f'configuring autoconnect: {wizard_data!r}')
def do_enable_autoconnect(self, wizard_data: dict):
# NETWORK_AUTO_CONNECT will only get explicitly set True, 'autoconnect': False means
# the user requested manual server configuration
self._logger.debug(f'enabling autoconnect: {wizard_data!r}')
assert wizard_data.get('autoconnect'), wizard_data
if self._daemon.config.cv.NETWORK_AUTO_CONNECT.is_modifiable():
if wizard_data.get('autoconnect') is not None:
self._daemon.config.NETWORK_AUTO_CONNECT = wizard_data.get('autoconnect')
self._daemon.config.NETWORK_AUTO_CONNECT = True
def start(self, *, start_viewstate: WizardViewState = None) -> WizardViewState:
self.reset()

View File

@@ -81,7 +81,7 @@ class ServerConnectWizardTestCase(WizardTestCase):
self.assertFalse(w.is_last_view(v_init.view, d))
v = w.resolve_next(v_init.view, d)
self.assertEqual('server_config', v.view)
self.assertEqual(False, self.config.NETWORK_AUTO_CONNECT)
self.assertFalse(self.config.cv.NETWORK_AUTO_CONNECT.is_set())
async def test_proxy(self):
w = ServerConnectWizard(DaemonMock(self.config))
@@ -110,7 +110,7 @@ class ServerConnectWizardTestCase(WizardTestCase):
self.assertFalse(w.is_last_view(v_init.view, d))
v = w.resolve_next(v_init.view, d)
self.assertEqual('proxy_config', v.view)
self.assertEqual(False, self.config.NETWORK_AUTO_CONNECT)
self.assertFalse(self.config.cv.NETWORK_AUTO_CONNECT.is_set())
d_proxy = {'enabled': False}
d.update({'proxy': d_proxy})
v = w.resolve_next(v.view, d)