import os from PyQt6.QtWidgets import QLabel, QPushButton, QWidget from PyQt6.QtGui import QPixmap from PyQt6.QtCore import Qt, QTimer from core.services.helpers.setup_sudo_scripts import auto_install_sudo_script, test_if_in_sudo_folder from core.services.helpers.manage_assets import sudo_assets_folder_setup from core.models.Result import Result, ResultError import sys from gui.v2.ui.pages.Page import Page class NetworkingSetupPage(Page): def __init__(self, page_stack, main_window=None, parent=None): super().__init__("NetworkingSetup", page_stack, main_window, parent) self.btn_path = main_window.btn_path self.update_status = main_window self.manual_scripts_ready = False self.button_next.setVisible(True) self.button_next.clicked.connect(self.go_to_install) self._setup_ui() 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;") subtitle = QLabel( "Optional privileged networking helpers", self) subtitle.setGeometry(140, 108, 560, 24) subtitle.setStyleSheet("font-size: 14px; color: #d8ffff;") description = QLabel( "These firewall and managed-DNS helpers are separate bash scripts. " "They stay outside the AppImage Python runtime, and if installed they are placed " "in sudo-protected folders owned by root.", self) description.setGeometry(80, 152, 640, 72) description.setWordWrap(True) description.setStyleSheet("font-size: 15px; color: cyan;") manual_panel = self._option_panel(74, 248, "Option 1", "Manual review") manual_text = QLabel( "Copy the scripts to Downloads, review them, then run sudo bash setup.sh yourself.", manual_panel) manual_text.setGeometry(24, 76, 252, 48) manual_text.setWordWrap(True) manual_text.setStyleSheet("font-size: 13px; color: #d8ffff;") self.manual_button = QPushButton("Get scripts", manual_panel) self.manual_button.setGeometry(24, 132, 252, 38) self.manual_button.setStyleSheet(self._button_style("#007AFF", "#0056CC")) self.manual_button.clicked.connect(self.handle_manual_setup) auto_panel = self._option_panel(426, 248, "Option 2", "Automated installer") 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.setWordWrap(True) auto_text.setStyleSheet("font-size: 13px; color: #d8ffff;") self.auto_button = QPushButton("Automated installer", auto_panel) self.auto_button.setGeometry(24, 132, 252, 38) self.auto_button.setStyleSheet(self._button_style("#16a085", "#117a65")) self.auto_button.clicked.connect(self.install_sudo_scripts_automatically) 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;") def _option_panel(self, x, y, label, title): panel = QWidget(self) panel.setObjectName("networkingOptionPanel") panel.setGeometry(x, y, 300, 186) panel.setStyleSheet(""" QWidget#networkingOptionPanel { background-color: #17323d; border: 1px solid #2c7a8d; border-radius: 6px; } """) 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;") 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;") return panel def _icon_label(self, icon_name, size, parent): label = QLabel(parent) icon_path = os.path.join(self.btn_path, icon_name) label.setPixmap(QPixmap(icon_path).scaled( size, size, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) label.setFixedSize(size, size) label.setStyleSheet("border: none;") return label def _button_style(self, background, hover): return f""" QPushButton {{ background: {background}; color: #f4ffff; border: none; border-radius: 4px; font-size: 12px; font-weight: bold; padding: 4px 8px; }} QPushButton:hover {{ background: {hover}; }} QPushButton:disabled {{ background: #3f4954; color: #94a3ad; }} """ def _set_status(self, message, color="#d8ffff"): self.status_label.setText(message) self.status_label.setStyleSheet(f"font-size: 13px; color: {color};") self.update_status.update_status(message) def _result_is_valid(self, result: Result): if hasattr(result, "valid"): return result.valid if result is None: return True return bool(result) def _result_message(self, result: Result, fallback): return getattr(result, "message", fallback) def handle_manual_setup(self): if self.manual_scripts_ready: self.confirm_sudo_scripts() return results = sudo_assets_folder_setup() if not self._result_is_valid(results): self._set_status( f"Could not copy scripts: {self._result_message(results, 'Unknown error')}", "#ff6b6b") return self.manual_scripts_ready = True self.manual_button.setText("Confirm manual install") self._set_status( "Copied to Downloads/hydraveil_sudo_scripts. Review them, run 'sudo bash setup.sh', then click Confirm manual install.", "#d8ffff") def confirm_sudo_scripts(self): confirmed = test_if_in_sudo_folder() if confirmed.valid: self._set_status("Confirmed it worked. Continuing to prerequisite installation.", "#2ecc71") QTimer.singleShot(600, self.go_to_install) else: self._set_status( f"I'm sorry it did not work, {confirmed.message}", "#ff6b6b") def install_sudo_scripts_automatically(self): results = auto_install_sudo_script() if results.valid: confirmed = test_if_in_sudo_folder() if confirmed.valid: self._set_status("The setup script ran successfully. Continuing to prerequisite installation.", "#2ecc71") QTimer.singleShot(600, self.go_to_install) else: self._set_status( f"I'm sorry it did not work, {confirmed.message}", "#ff6b6b") else: self._set_status( f"Setup script did NOT work because {results.message}", "#ff6b6b") def go_to_install(self): self.custom_window.navigator.navigate("install_system_package") install_page = self.custom_window.navigator.get_cached("install_system_package") if install_page is not None: install_page.configure(package_name='all', distro='debian') def back_to_welcome(self): self.custom_window.navigator.navigate("welcome")