Merge branch 'reset'

This commit is contained in:
2026-02-19 08:55:53 +01:00
5 changed files with 173 additions and 4 deletions

View File

@@ -296,6 +296,7 @@ Pane {
dialog.open()
}
}
}
}

View File

@@ -50,9 +50,73 @@ Item {
}
}
Label {
text: qsTr("Server")
enabled: address_tf.enabled
RowLayout {
Layout.fillWidth: true
Label {
text: qsTr("Server")
enabled: address_tf.enabled
Layout.fillWidth: true
}
ToolButton {
icon.source: '../../../icons/delete.png'
ToolTip.text: qsTr('Reset network data')
ToolTip.visible: hovered
onClicked: resetMenu.open()
Menu {
id: resetMenu
MenuItem {
text: qsTr('SSL certificates')
onTriggered: {
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Are you sure?'),
text: qsTr('This will remove cached SSL certificates for servers and reconnect to fetch them again.'),
yesno: true
})
dialog.accepted.connect(function() {
var removed = Network.clearPinnedServerCertificates()
var msg = removed < 0
? qsTr('Failed to reset SSL certificates.')
: removed > 0
? qsTr('%1 certificate files were removed.').arg(removed)
: qsTr('No cached certificate files were found.')
app.messageDialog.createObject(app, {
title: qsTr('Reset SSL certificates'),
text: msg
}).open()
})
dialog.open()
}
}
MenuItem {
text: qsTr('Known servers')
onTriggered: {
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Are you sure?'),
text: qsTr('This will remove the list of known servers.'),
yesno: true
})
dialog.accepted.connect(function() {
var removed = Network.clearRecentServers()
var msg = removed < 0
? qsTr('Failed to reset known servers.')
: removed > 0
? qsTr('%1 server(s) were removed.').arg(removed)
: qsTr('No known servers were found.')
app.messageDialog.createObject(app, {
title: qsTr('Reset known servers'),
text: msg
}).open()
})
dialog.open()
}
}
}
}
}
TextHighlightPane {

View File

@@ -306,3 +306,19 @@ class QENetwork(QObject, QtEventListener):
@pyqtSlot()
def probeTor(self):
ProxySettings.probe_tor(self.torProbeFinished.emit) # via signal
@pyqtSlot(result=int)
def clearPinnedServerCertificates(self):
try:
return self.network.run_from_another_thread(self.network.clear_pinned_server_certs())
except Exception:
self._logger.exception("failed to clear pinned server certificates")
return -1
@pyqtSlot(result=int)
def clearRecentServers(self):
try:
return self.network.clear_recent_servers()
except Exception:
self._logger.exception("failed to clear recent servers")
return -1

View File

@@ -29,7 +29,7 @@ from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt6.QtWidgets import (
QTreeWidget, QTreeWidgetItem, QMenu, QGridLayout, QComboBox, QLineEdit, QDialog, QVBoxLayout, QHeaderView,
QCheckBox, QTabWidget, QWidget, QLabel, QPushButton, QHBoxLayout,
QListWidget, QListWidgetItem,
QListWidget, QListWidgetItem, QMessageBox,
)
from PyQt6.QtGui import QIntValidator
@@ -444,6 +444,16 @@ class ServerWidget(QWidget, QtEventListener):
self.layout().addWidget(self.nodes_list_widget)
self.nodes_list_widget.update()
self.clear_certs_button = QPushButton(_('Reset SSL certificates'))
self.clear_certs_button.clicked.connect(self.clear_pinned_server_certs)
self.clear_servers_button = QPushButton(_('Reset known servers'))
self.clear_servers_button.clicked.connect(self.clear_recent_servers)
buttons = QHBoxLayout()
buttons.addStretch(1)
buttons.addWidget(self.clear_certs_button)
buttons.addWidget(self.clear_servers_button)
self.layout().addLayout(buttons)
self.register_callbacks()
self.destroyed.connect(lambda: self.unregister_callbacks())
@@ -584,6 +594,54 @@ class ServerWidget(QWidget, QtEventListener):
_logger.debug(f"set_server: {new_net_params=}")
self.network.run_from_another_thread(self.network.set_parameters(new_net_params))
def clear_pinned_server_certs(self):
result = QMessageBox.question(
self,
_('Reset SSL certificates'),
_('This will remove cached SSL certificates for servers and reconnect to fetch them again.')
+ '\n\n'
+ _('Do you want to continue?'),
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No,
)
if result != QMessageBox.StandardButton.Yes:
return
try:
removed = self.network.run_from_another_thread(self.network.clear_pinned_server_certs())
except Exception as e:
_logger.exception("failed to clear pinned server certificates")
QMessageBox.critical(self, _('Reset SSL certificates'), str(e))
return
if removed > 0:
msg = _('{} certificate files were removed.').format(removed)
else:
msg = _('No cached certificate files were found.')
QMessageBox.information(self, _('Reset SSL certificates'), msg)
def clear_recent_servers(self):
result = QMessageBox.question(
self,
_('Reset known servers'),
_('This will remove the list of known servers.')
+ '\n\n'
+ _('Do you want to continue?'),
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.No,
)
if result != QMessageBox.StandardButton.Yes:
return
try:
removed = self.network.clear_recent_servers()
except Exception as e:
_logger.exception("failed to clear recent servers")
QMessageBox.critical(self, _('Reset known servers'), str(e))
return
if removed > 0:
msg = _('{} server(s) were removed.').format(removed)
else:
msg = _('No known servers were found.')
QMessageBox.information(self, _('Reset known servers'), msg)
class NostrWidget(QWidget, QtEventListener):

View File

@@ -408,6 +408,36 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
"""Our guess whether the device has Internet-connectivity."""
return self._has_ever_managed_to_connect_to_server
def clear_recent_servers(self) -> int:
"""Clear the list of recently used servers."""
with self.recent_servers_lock:
count = len(self._recent_servers)
self._recent_servers = []
self._save_recent_servers()
self.logger.info(f"cleared {count} recent server(s)")
return count
async def clear_pinned_server_certs(self) -> int:
"""Delete cached server SSL certs and reconnect interfaces."""
certs_dir = os.path.join(self.config.path, 'certs')
util.make_dir(certs_dir)
removed = 0
for entry in os.scandir(certs_dir):
if not entry.is_file():
continue
try:
os.unlink(entry.path)
removed += 1
except OSError as e:
self.logger.warning(f"failed to delete cert file {entry.path!r}: {e!r}")
self.logger.info(f"removed {removed} cached server cert(s)")
if removed:
with self.interfaces_lock:
interfaces = list(self.interfaces.values())
for iface in interfaces:
await self._close_interface(iface)
return removed
def has_channel_db(self):
return self.channel_db is not None