From 3483b5120076961c2c4ae45256a59209e083e547 Mon Sep 17 00:00:00 2001 From: JOhn Date: Sat, 25 Jul 2026 08:20:26 -0400 Subject: [PATCH] update: added new firewall and dns page --- gui/resources/images/networking_auto.png | Bin 0 -> 758 bytes gui/resources/images/networking_manual.png | Bin 0 -> 1156 bytes gui/resources/images/networking_shield.png | Bin 0 -> 1632 bytes gui/v2/infrastructure/page_registry.py | 1 + gui/v2/ui/pages/networking_setup_page.py | 191 +++++++++++++++++++++ gui/v2/ui/pages/welcome_page.py | 13 +- 6 files changed, 197 insertions(+), 8 deletions(-) create mode 100755 gui/resources/images/networking_auto.png create mode 100755 gui/resources/images/networking_manual.png create mode 100755 gui/resources/images/networking_shield.png create mode 100755 gui/v2/ui/pages/networking_setup_page.py diff --git a/gui/resources/images/networking_auto.png b/gui/resources/images/networking_auto.png new file mode 100755 index 0000000000000000000000000000000000000000..ab027113acec96b5b2ba3628bee47cad0ac3982e GIT binary patch literal 758 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 literal 0 HcmV?d00001 diff --git a/gui/v2/infrastructure/page_registry.py b/gui/v2/infrastructure/page_registry.py index 9d761b2..3fa915f 100755 --- a/gui/v2/infrastructure/page_registry.py +++ b/gui/v2/infrastructure/page_registry.py @@ -1,6 +1,7 @@ PAGE_REGISTRY = { "blank": ("gui.v2.ui.pages._blank_page", "BlankPage"), "welcome": ("gui.v2.ui.pages.welcome_page", "WelcomePage"), + "networking_setup": ("gui.v2.ui.pages.networking_setup_page", "NetworkingSetupPage"), "menu": ("gui.v2.ui.pages.menu_page", "MenuPage"), "protocol": ("gui.v2.ui.pages.protocol_page", "ProtocolPage"), "hidetor": ("gui.v2.ui.pages.hidetor_page", "HidetorPage"), diff --git a/gui/v2/ui/pages/networking_setup_page.py b/gui/v2/ui/pages/networking_setup_page.py new file mode 100755 index 0000000..3a7acf6 --- /dev/null +++ b/gui/v2/ui/pages/networking_setup_page.py @@ -0,0 +1,191 @@ +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") diff --git a/gui/v2/ui/pages/welcome_page.py b/gui/v2/ui/pages/welcome_page.py index c7d0c83..2045c3c 100755 --- a/gui/v2/ui/pages/welcome_page.py +++ b/gui/v2/ui/pages/welcome_page.py @@ -13,7 +13,7 @@ class WelcomePage(Page): self.btn_path = main_window.btn_path self.update_status = main_window self.ui_elements = [] - self.button_next.clicked.connect(self.go_to_install) + self.button_next.clicked.connect(self.go_to_networking_setup) self.button_next.setVisible(True) self._setup_welcome_ui() self._setup_stats_display() @@ -30,7 +30,7 @@ class WelcomePage(Page): welcome_msg = QLabel( "Before we begin your journey, we need to set up a few essential components. " - "Click 'Next' to take you to the installation page.", self) + "Click 'Next' to review the optional networking setup.", self) welcome_msg.setGeometry(40, 100, 720, 80) welcome_msg.setWordWrap(True) welcome_msg.setStyleSheet(""" @@ -95,7 +95,7 @@ class WelcomePage(Page): "font-size: 16px; font-weight: bold; color: #2c3e50;") title_layout.addWidget(title_label) - status_indicator = QLabel("●") + status_indicator = QLabel(chr(9679)) status_indicator.setStyleSheet("color: #2ecc71; font-size: 16px;") title_layout.addWidget(status_indicator) @@ -117,8 +117,5 @@ class WelcomePage(Page): grid_layout.addWidget(stat_widget, row, col) - 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 go_to_networking_setup(self): + self.custom_window.navigator.navigate("networking_setup")