From 97f09ec42e1478c5e0a8358c809222ab831aaae3 Mon Sep 17 00:00:00 2001 From: JOhn Date: Sun, 26 Jul 2026 19:01:07 -0400 Subject: [PATCH] update: new settings connection tab --- gui/__main__.py | 0 gui/v2/actions/settings_data.py | 24 ++- gui/v2/ui/pages/networking_setup_page.py | 28 +-- gui/v2/ui/pages/settings_page.py | 213 +++++++++++++++++++---- 4 files changed, 216 insertions(+), 49 deletions(-) mode change 100644 => 100755 gui/__main__.py diff --git a/gui/__main__.py b/gui/__main__.py old mode 100644 new mode 100755 diff --git a/gui/v2/actions/settings_data.py b/gui/v2/actions/settings_data.py index f86c03d..883da48 100755 --- a/gui/v2/actions/settings_data.py +++ b/gui/v2/actions/settings_data.py @@ -5,7 +5,6 @@ from core.Constants import Constants from core.controllers.ConfigurationController import ConfigurationController from core.controllers.PolicyController import PolicyController from core.controllers.ProfileController import ProfileController -from core.services.networking.systemwide.systemwide_utils import get_firewall_setting from gui.v2.actions.config import load_gui_config from gui.v2.actions.profile_order import normalize_profile_order @@ -13,15 +12,28 @@ from gui.v2.actions.ticket_failure import get_ticket_verification_failure -def read_firewall_setting(): +def read_connection_setting(gui_config_file, key): try: - firewall_setting = get_firewall_setting() - return firewall_setting + config = load_gui_config(gui_config_file) + if config and "connection_settings" in config: + return bool(config["connection_settings"].get(key, False)) except Exception: pass return False +def read_firewall_setting(gui_config_file=None): + if gui_config_file is None: + return False + return read_connection_setting(gui_config_file, "firewall_enabled") + + +def read_managed_dns_setting(gui_config_file=None): + if gui_config_file is None: + return False + return read_connection_setting(gui_config_file, "managed_dns_enabled") + + def read_systemwide_enabled(): try: privilege_policy = PolicyController.get('privilege') @@ -56,7 +68,8 @@ def prepare(gui_config_file): "endpoint_verification_enabled": endpoint_verification_enabled, "systemwide_enabled": read_systemwide_enabled(), "bwrap_enabled": read_bwrap_enabled(), - "firewall_setting": read_firewall_setting(), + "firewall_setting": read_firewall_setting(gui_config_file), + "managed_dns_setting": read_managed_dns_setting(gui_config_file), "gui_config": load_gui_config(gui_config_file), "ticket_failure": get_ticket_verification_failure(gui_config_file), } @@ -71,6 +84,7 @@ def empty_payload(): "systemwide_enabled": False, "bwrap_enabled": False, "firewall_setting": False, + "managed_dns_setting": False, "gui_config": None, "ticket_failure": None, } diff --git a/gui/v2/ui/pages/networking_setup_page.py b/gui/v2/ui/pages/networking_setup_page.py index 3a7acf6..2827e58 100755 --- a/gui/v2/ui/pages/networking_setup_page.py +++ b/gui/v2/ui/pages/networking_setup_page.py @@ -19,23 +19,30 @@ class NetworkingSetupPage(Page): self.btn_path = main_window.btn_path self.update_status = main_window self.manual_scripts_ready = False + self.setStyleSheet("font-family: Arial;") + self.button_next.clicked.disconnect(self.gestionar_next) self.button_next.setVisible(True) self.button_next.clicked.connect(self.go_to_install) self._setup_ui() + def showEvent(self, event): + super().showEvent(event) + self.button_next.setVisible(True) + self.button_next.raise_() + def _setup_ui(self): header_icon = self._icon_label("networking_shield.png", 48, self) header_icon.setGeometry(74, 66, 48, 48) title = QLabel("Firewall & Managed-DNS Setup", self) title.setGeometry(138, 68, 590, 44) - title.setStyleSheet("font-size: 26px; font-weight: bold; color: cyan;") + title.setStyleSheet("font-family: Arial; font-size: 26px; font-weight: bold; color: cyan;") subtitle = QLabel( "Optional privileged networking helpers", self) subtitle.setGeometry(140, 108, 560, 24) - subtitle.setStyleSheet("font-size: 14px; color: #d8ffff;") + subtitle.setStyleSheet("font-family: Arial; font-size: 14px; color: #d8ffff;") description = QLabel( "These firewall and managed-DNS helpers are separate bash scripts. " @@ -44,7 +51,7 @@ class NetworkingSetupPage(Page): self) description.setGeometry(80, 152, 640, 72) description.setWordWrap(True) - description.setStyleSheet("font-size: 15px; color: cyan;") + description.setStyleSheet("font-family: Arial; font-size: 15px; color: cyan;") manual_panel = self._option_panel(74, 248, "Option 1", "Manual review") manual_text = QLabel( @@ -52,7 +59,7 @@ class NetworkingSetupPage(Page): manual_panel) manual_text.setGeometry(24, 76, 252, 48) manual_text.setWordWrap(True) - manual_text.setStyleSheet("font-size: 13px; color: #d8ffff;") + manual_text.setStyleSheet("font-family: Arial; font-size: 13px; color: #d8ffff;") self.manual_button = QPushButton("Get scripts", manual_panel) self.manual_button.setGeometry(24, 132, 252, 38) @@ -63,9 +70,9 @@ class NetworkingSetupPage(Page): auto_text = QLabel( "Let HydraVeil run the installer, then test that the scripts reached the sudo folder.", auto_panel) - auto_text.setGeometry(24, 76, 252, 48) + auto_text.setGeometry(24, 76, 265, 48) auto_text.setWordWrap(True) - auto_text.setStyleSheet("font-size: 13px; color: #d8ffff;") + auto_text.setStyleSheet("font-family: Arial; font-size: 13px; color: #d8ffff;") self.auto_button = QPushButton("Automated installer", auto_panel) self.auto_button.setGeometry(24, 132, 252, 38) @@ -75,7 +82,7 @@ class NetworkingSetupPage(Page): self.status_label = QLabel("Choose manual or automated setup, or press Next to skip and continue.", self) self.status_label.setGeometry(82, 462, 636, 38) self.status_label.setWordWrap(True) - self.status_label.setStyleSheet("font-size: 13px; color: #d8ffff;") + self.status_label.setStyleSheet("font-family: Arial; font-size: 13px; color: #d8ffff;") def _option_panel(self, x, y, label, title): @@ -92,11 +99,11 @@ class NetworkingSetupPage(Page): option_label = QLabel(label, panel) option_label.setGeometry(24, 20, 120, 20) - option_label.setStyleSheet("font-size: 11px; font-weight: bold; color: #8de9ff; border: none;") + option_label.setStyleSheet("font-family: Arial; font-size: 11px; font-weight: bold; color: #8de9ff; border: none;") title_label = QLabel(title, panel) title_label.setGeometry(24, 42, 240, 28) - title_label.setStyleSheet("font-size: 18px; font-weight: bold; color: cyan; border: none;") + title_label.setStyleSheet("font-family: Arial; font-size: 18px; font-weight: bold; color: cyan; border: none;") return panel @@ -116,6 +123,7 @@ class NetworkingSetupPage(Page): color: #f4ffff; border: none; border-radius: 4px; + font-family: Arial; font-size: 12px; font-weight: bold; padding: 4px 8px; @@ -131,7 +139,7 @@ class NetworkingSetupPage(Page): def _set_status(self, message, color="#d8ffff"): self.status_label.setText(message) - self.status_label.setStyleSheet(f"font-size: 13px; color: {color};") + self.status_label.setStyleSheet(f"font-family: Arial; font-size: 13px; color: {color};") self.update_status.update_status(message) def _result_is_valid(self, result: Result): diff --git a/gui/v2/ui/pages/settings_page.py b/gui/v2/ui/pages/settings_page.py index b5c39e3..06ceb04 100755 --- a/gui/v2/ui/pages/settings_page.py +++ b/gui/v2/ui/pages/settings_page.py @@ -17,6 +17,7 @@ from core.Constants import Constants from core.controllers.ConfigurationController import ConfigurationController from core.controllers.PolicyController import PolicyController from core.controllers.ProfileController import ProfileController +from core.controllers.SystemStateController import SystemStateController from core.controllers.tickets.UseTicketController import ( do_we_use_a_random_ticket, get_unused_tickets, @@ -31,7 +32,7 @@ from core.Errors import ( PolicyRevocationError, ) from core.errors.logger import logger as core_logger -from core.services.networking.systemwide.systemwide_utils import get_firewall_setting +from core.services.helpers.setup_sudo_scripts import test_if_in_sudo_folder from gui.v2.actions import settings_data from gui.v2.actions.key_interpretation import interpret_key_results @@ -1521,8 +1522,12 @@ class Settings(Page): def show_connection_page(self): core_logger.info("User navigated to Settings -> Connection") + if hasattr(self, "connection_gate_status"): + self.load_firewall_settings() + self.load_managed_dns_settings() + self.refresh_connection_settings_gate() self.content_layout.setCurrentWidget(self.connection_page) - self._select_menu_button("Connection Page") + self._select_menu_button("Connections") def show_logs_page(self): core_logger.info("User navigated to Settings -> Error Logs") @@ -2114,7 +2119,7 @@ class Settings(Page): def load_firewall_settings(self, enabled=None): if enabled is None: - enabled = settings_data.load(read_firewall_setting) + enabled = self.read_gui_connection_setting("firewall_enabled") self.firewall_toggle.setChecked(enabled) if enabled: self.firewall_status_value.setText("Enabled") @@ -2126,6 +2131,20 @@ class Settings(Page): f"color: #e67e22; font-size: 14px; {self.font_style}") + def load_managed_dns_settings(self, enabled=None): + if enabled is None: + enabled = self.read_gui_connection_setting("managed_dns_enabled") + self.managed_dns_toggle.setChecked(enabled) + if enabled: + self.managed_dns_status_value.setText("Enabled") + self.managed_dns_status_value.setStyleSheet( + f"color: #2ecc71; font-size: 14px; {self.font_style}") + else: + self.managed_dns_status_value.setText("Disabled") + self.managed_dns_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") + + def save_bwrap_settings(self): enable = self.bwrap_toggle.isChecked() try: @@ -2153,28 +2172,108 @@ class Settings(Page): f"color: red; font-size: 14px; {self.font_style}") - def save_firewall_settings(self): - enable = self.firewall_toggle.isChecked() + def save_connection_settings(self): + can_modify, message, _ = self.connection_settings_gate() + if not can_modify: + self.connection_gate_status.setText(message) + self.connection_gate_status.setStyleSheet( + f"color: #ff6b6b; font-size: 12px; {self.font_style}") + self.set_connection_controls_enabled(False) + self.update_status.update_status(message) + return + + firewall_enabled = self.firewall_toggle.isChecked() + managed_dns_enabled = self.managed_dns_toggle.isChecked() try: - if enable: - ConfigurationController.change_firewall(True) - self.firewall_status_value.setText("Enabled") - else: - ConfigurationController.change_firewall(False) - self.firewall_status_value.setText("Disabled") + self.save_gui_connection_settings(firewall_enabled, managed_dns_enabled) + self.load_firewall_settings(firewall_enabled) + self.load_managed_dns_settings(managed_dns_enabled) self.update_status.update_status( - "Firewall settings updated") + "Connection settings updated") except CommandNotFoundError as e: self.firewall_status_value.setText(str(e)) self.firewall_status_value.setStyleSheet( f"color: red; font-size: 14px; {self.font_style}") except Exception as e: - print(e) - self.firewall_status_value.setText(f"Failed to update firewall setting {e}") + self.firewall_status_value.setText(f"Failed to update connection settings {e}") self.firewall_status_value.setStyleSheet( f"color: red; font-size: 14px; {self.font_style}") + def save_firewall_settings(self): + self.save_connection_settings() + + + def read_gui_connection_setting(self, key): + try: + config = self.update_status._load_gui_config() + if config and "connection_settings" in config: + return bool(config["connection_settings"].get(key, False)) + except Exception: + pass + return False + + + def save_gui_connection_settings(self, firewall_enabled, managed_dns_enabled): + config = self.update_status._load_gui_config() + if config is None: + config = {} + if "connection_settings" not in config: + config["connection_settings"] = {} + config["connection_settings"]["firewall_enabled"] = firewall_enabled + config["connection_settings"]["managed_dns_enabled"] = managed_dns_enabled + self.update_status._save_gui_config(config) + self._prepared["firewall_setting"] = firewall_enabled + self._prepared["managed_dns_setting"] = managed_dns_enabled + + + def connection_settings_gate(self): + installed, install_message = self.networking_scripts_installed() + if not installed: + return False, f"Firewall and managed-DNS helpers are not installed. {install_message}", True + if self.has_active_systemwide_profile(): + return False, "Disable the active systemwide profile before changing firewall or managed-DNS settings.", False + return True, "Firewall and managed-DNS helpers are installed. No active systemwide profile detected.", False + + + def networking_scripts_installed(self): + try: + result = test_if_in_sudo_folder() + if result.valid: + return True, "Installed." + return False, result.message + except Exception as e: + return False, str(e) + + + def has_active_systemwide_profile(self): + try: + return SystemStateController.get() is not None + except Exception: + return True + + + def set_connection_controls_enabled(self, enabled): + for widget_name in ("firewall_toggle", "managed_dns_toggle", "connection_save_button"): + widget = getattr(self, widget_name, None) + if widget is not None: + widget.setEnabled(enabled) + + + def refresh_connection_settings_gate(self): + can_modify, message, show_install = self.connection_settings_gate() + self.connection_gate_status.setText(message) + color = "#2ecc71" if can_modify else "#ff6b6b" + self.connection_gate_status.setStyleSheet( + f"color: {color}; font-size: 12px; {self.font_style}") + self.set_connection_controls_enabled(can_modify) + self.connection_install_button.setVisible(show_install) + + + def open_networking_installer(self): + self.custom_window.navigator.navigate("networking_setup") + + def load_registrations_settings(self) -> None: try: config = self._prepared_value( @@ -2242,7 +2341,7 @@ class Settings(Page): def create_connection_page(self): page = QWidget() layout = QVBoxLayout(page) - layout.setSpacing(20) + layout.setSpacing(16) layout.setContentsMargins(20, 20, 20, 20) title = QLabel("CONNECTION PAGE") @@ -2251,43 +2350,89 @@ class Settings(Page): layout.addWidget(title) description = QLabel( - "Control connection settings such as the firewall.") + "Control firewall and managed-DNS behavior for systemwide profiles.") description.setWordWrap(True) description.setStyleSheet( f"color: white; font-size: 14px; {self.font_style}") layout.addWidget(description) - status_layout = QHBoxLayout() - status_label = QLabel("Current status:") - status_label.setStyleSheet( + self.connection_gate_status = QLabel("") + self.connection_gate_status.setWordWrap(True) + self.connection_gate_status.setStyleSheet( + f"color: #e67e22; font-size: 12px; {self.font_style}") + layout.addWidget(self.connection_gate_status) + + self.connection_install_button = QPushButton("Install networking helpers") + self.connection_install_button.setFixedSize(190, 38) + self.connection_install_button.setStyleSheet(f""" + QPushButton {{ + background: #007AFF; + color: white; + border: none; + border-radius: 5px; + font-weight: bold; + {self.font_style} + }} + QPushButton:hover {{ + background: #0056CC; + }} + """) + self.connection_install_button.clicked.connect(self.open_networking_installer) + layout.addWidget(self.connection_install_button) + + firewall_status_layout = QHBoxLayout() + firewall_status_label = QLabel("Firewall status:") + firewall_status_label.setStyleSheet( f"color: white; font-size: 14px; {self.font_style}") self.firewall_status_value = QLabel("") self.firewall_status_value.setStyleSheet( f"color: #e67e22; font-size: 14px; {self.font_style}") - status_layout.addWidget(status_label) - status_layout.addWidget(self.firewall_status_value) - status_layout.addStretch() - layout.addLayout(status_layout) + firewall_status_layout.addWidget(firewall_status_label) + firewall_status_layout.addWidget(self.firewall_status_value) + firewall_status_layout.addStretch() + layout.addLayout(firewall_status_layout) - toggle_layout = QHBoxLayout() + dns_status_layout = QHBoxLayout() + dns_status_label = QLabel("Managed-DNS status:") + dns_status_label.setStyleSheet( + f"color: white; font-size: 14px; {self.font_style}") + self.managed_dns_status_value = QLabel("") + self.managed_dns_status_value.setStyleSheet( + f"color: #e67e22; font-size: 14px; {self.font_style}") + dns_status_layout.addWidget(dns_status_label) + dns_status_layout.addWidget(self.managed_dns_status_value) + dns_status_layout.addStretch() + layout.addLayout(dns_status_layout) + + firewall_toggle_layout = QHBoxLayout() self.firewall_toggle = QCheckBox("Enable Firewall Automatically when Systemwide Profiles are Activated") self.firewall_toggle.setStyleSheet(self.get_checkbox_style()) - toggle_layout.addWidget(self.firewall_toggle) - toggle_layout.addStretch() - layout.addLayout(toggle_layout) + firewall_toggle_layout.addWidget(self.firewall_toggle) + firewall_toggle_layout.addStretch() + layout.addLayout(firewall_toggle_layout) - save_button = QPushButton() - save_button.setFixedSize(75, 46) - save_button.setIcon(QIcon(os.path.join(self.btn_path, "save.png"))) - save_button.setIconSize(QSize(75, 46)) - save_button.clicked.connect(self.save_firewall_settings) + dns_toggle_layout = QHBoxLayout() + self.managed_dns_toggle = QCheckBox("Enable Managed-DNS Automatically when Systemwide Profiles are Activated") + self.managed_dns_toggle.setStyleSheet(self.get_checkbox_style()) + dns_toggle_layout.addWidget(self.managed_dns_toggle) + dns_toggle_layout.addStretch() + layout.addLayout(dns_toggle_layout) + + self.connection_save_button = QPushButton() + self.connection_save_button.setFixedSize(75, 46) + self.connection_save_button.setIcon(QIcon(os.path.join(self.btn_path, "save.png"))) + self.connection_save_button.setIconSize(QSize(75, 46)) + self.connection_save_button.clicked.connect(self.save_connection_settings) button_layout = QHBoxLayout() - button_layout.addWidget(save_button) + button_layout.addWidget(self.connection_save_button) button_layout.addStretch() layout.addLayout(button_layout) layout.addStretch() self.load_firewall_settings( - self._prepared_value("firewall_setting", settings_data.read_firewall_setting)) + self._prepared_value("firewall_setting", lambda: self.read_gui_connection_setting("firewall_enabled"))) + self.load_managed_dns_settings( + self._prepared_value("managed_dns_setting", lambda: self.read_gui_connection_setting("managed_dns_enabled"))) + self.refresh_connection_settings_gate() return page