From ec73b809fa9c8e5627807ad6321f9359aa4a469b Mon Sep 17 00:00:00 2001 From: CrazyTodd-one <263771835+CrazyTodd-one@users.noreply.github.com> Date: Sat, 21 Mar 2026 04:14:51 -0400 Subject: [PATCH] Fix WiFi detection when wired connection is primary (#1775) Check all active NetworkManager connections for WiFi, not just the primary one. When a laptop is docked (wired + WiFi), the primary connection is wired, so the WiFi SSID was never detected and network-based backup restrictions were bypassed. - Add get_active_connections_paths() to iterate ActiveConnections - Handle per-connection DBus failures gracefully - Add tests for docking station scenario and connection failure resilience Co-Authored-By: Claude Opus 4.6 (1M context) --- src/vorta/network_status/network_manager.py | 30 +++++++++------ tests/network_manager/test_network_manager.py | 38 +++++++++++++++++-- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/vorta/network_status/network_manager.py b/src/vorta/network_status/network_manager.py index 601afe4e5..1d68fd722 100644 --- a/src/vorta/network_status/network_manager.py +++ b/src/vorta/network_status/network_manager.py @@ -38,18 +38,23 @@ def is_network_active(self) -> bool: return True def get_current_wifi(self) -> str | None: - # Only check the primary connection. VPN over WiFi will still show the WiFi as Primary Connection. - # We don't check all active connections, as NM won't disable WiFi when connecting a cable. + # Check all active connections for WiFi, not just the primary one. + # When connected via both WiFi and wired (e.g. docking station), the primary + # connection may be wired, but the WiFi SSID is still needed for network-based + # backup restrictions. See #1775. try: - active_connection_path = self._nm.get_primary_connection_path() - if not active_connection_path: - return None - active_connection = self._nm.get_active_connection_info(active_connection_path) - if active_connection.type == '802-11-wireless': - settings = self._nm.get_settings(active_connection.connection) - ssid = self._get_ssid_from_settings(settings) - if ssid: - return ssid + active_paths = self._nm.get_active_connections_paths() + for active_connection_path in active_paths: + try: + active_connection = self._nm.get_active_connection_info(active_connection_path) + if active_connection.type == '802-11-wireless': + settings = self._nm.get_settings(active_connection.connection) + ssid = self._get_ssid_from_settings(settings) + if ssid: + return ssid + except DBusException: + logger.debug("Failed to get info for active connection %s", active_connection_path) + continue except DBusException: logger.exception("Failed to get currently connected WiFi network, assuming none") return None @@ -163,6 +168,9 @@ def get_network_state(self) -> NMState: def get_primary_connection_path(self) -> str | None: return read_dbus_property(self._nm, 'PrimaryConnection') + def get_active_connections_paths(self) -> list[str]: + return read_dbus_property(self._nm, 'ActiveConnections') or [] + def get_active_connection_info(self, active_connection_path: str) -> ActiveConnectionInfo: active_connection = self._get_iface(active_connection_path, 'org.freedesktop.NetworkManager.Connection.Active') return ActiveConnectionInfo( diff --git a/tests/network_manager/test_network_manager.py b/tests/network_manager/test_network_manager.py index 2a4f35fb6..9fcca52df 100644 --- a/tests/network_manager/test_network_manager.py +++ b/tests/network_manager/test_network_manager.py @@ -58,11 +58,11 @@ def test_is_network_metered(global_metered_status, expected, nm_monitor): {'ssid': bytes([84, 69, 83, 84])}, 'TEST', ), - ('/org/freedesktop/NetworkManager/ActiveConnection/2', '802-11-ethernet', {}, None), + ('/org/freedesktop/NetworkManager/ActiveConnection/2', '802-3-ethernet', {}, None), ], ) def test_get_current_wifi(connection_path, connection_type, type_settings, expected, nm_monitor): - nm_monitor._nm.get_primary_connection_path.return_value = connection_path + nm_monitor._nm.get_active_connections_paths.return_value = [connection_path] nm_monitor._nm.get_active_connection_info.return_value = ActiveConnectionInfo( connection='/org/freedesktop/NetworkManager/Settings/12', type=connection_type ) @@ -74,11 +74,43 @@ def test_get_current_wifi(connection_path, connection_type, type_settings, expec def test_get_current_wifi_with_no_connection(nm_monitor): - nm_monitor._nm.get_primary_connection_path.return_value = None + nm_monitor._nm.get_active_connections_paths.return_value = [] assert nm_monitor.get_current_wifi() is None +def test_get_current_wifi_with_wired_primary_and_wifi_active(nm_monitor): + """When wired is primary but WiFi is also active (e.g. docking station), WiFi SSID should be found. See #1775.""" + wired_path = '/org/freedesktop/NetworkManager/ActiveConnection/1' + wifi_path = '/org/freedesktop/NetworkManager/ActiveConnection/2' + nm_monitor._nm.get_active_connections_paths.return_value = [wired_path, wifi_path] + nm_monitor._nm.get_active_connection_info.side_effect = [ + ActiveConnectionInfo(connection='/org/freedesktop/NetworkManager/Settings/10', type='802-3-ethernet'), + ActiveConnectionInfo(connection='/org/freedesktop/NetworkManager/Settings/11', type='802-11-wireless'), + ] + nm_monitor._nm.get_settings.return_value = {'802-11-wireless': {'ssid': bytes([72, 79, 77, 69])}} + + result = nm_monitor.get_current_wifi() + + assert result == 'HOME' + + +def test_get_current_wifi_skips_failed_connection(nm_monitor): + """If one active connection throws DBusException, other connections should still be checked.""" + bad_path = '/org/freedesktop/NetworkManager/ActiveConnection/1' + good_path = '/org/freedesktop/NetworkManager/ActiveConnection/2' + nm_monitor._nm.get_active_connections_paths.return_value = [bad_path, good_path] + nm_monitor._nm.get_active_connection_info.side_effect = [ + DBusException("connection gone"), + ActiveConnectionInfo(connection='/org/freedesktop/NetworkManager/Settings/11', type='802-11-wireless'), + ] + nm_monitor._nm.get_settings.return_value = {'802-11-wireless': {'ssid': bytes([84, 69, 83, 84])}} + + result = nm_monitor.get_current_wifi() + + assert result == 'TEST' + + def test_get_known_wifis(nm_monitor): nm_monitor._nm.get_connections_paths.return_value = ['/org/freedesktop/NetworkManager/Settings/12'] nm_monitor._nm.get_settings.return_value = {