From e608c790ede4842f2541e6129582381a2c3bfd21 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 30 Nov 2025 21:22:49 +0100 Subject: [PATCH] update: added bwarp sidebar in settings / updated text in init screen --- gui/__main__.py | 148 +++++++++++++++++++++++++++++++++++++++--------- pyproject.toml | 2 +- 2 files changed, 121 insertions(+), 29 deletions(-) diff --git a/gui/__main__.py b/gui/__main__.py index 7b70edf..4f098d6 100755 --- a/gui/__main__.py +++ b/gui/__main__.py @@ -961,19 +961,17 @@ class CustomWindow(QMainWindow): self.disable_marquee() def check_first_launch(self): - - config_file = os.path.join(self.gui_config_home, '.first-run') - os.makedirs(Constants.HV_CONFIG_HOME, exist_ok=True) + config = self._load_gui_config() + if config is None: + config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} - is_first_launch = not os.path.exists(config_file) + is_first_launch = not config.get("first_launch", {}).get("completed", False) if is_first_launch: - try: - with open(config_file, 'w') as f: - f.write('launched') - except Exception as e: - print(f"Error writing to launch file: {e}") - + if "first_launch" not in config: + config["first_launch"] = {} + config["first_launch"]["completed"] = True + self._save_gui_config(config) return True else: return False @@ -999,17 +997,19 @@ class CustomWindow(QMainWindow): print(f"Error checking suggestible policies: {e}") def has_shown_fast_mode_prompt(self): - flag_file = os.path.join(self.gui_config_home, '.fast-mode-prompted') - return os.path.exists(flag_file) + config = self._load_gui_config() + if not config: + return False + return config.get("fast_mode", {}).get("prompt_shown", False) def mark_fast_mode_prompt_shown(self): - os.makedirs(self.gui_config_home, exist_ok=True) - flag_file = os.path.join(self.gui_config_home, '.fast-mode-prompted') - try: - with open(flag_file, 'w') as f: - f.write('shown') - except Exception as e: - print(f"Error writing fast mode flag: {e}") + config = self._load_gui_config() + if config is None: + config = {"logging": {"gui_logging_enabled": False, "log_level": "INFO"}} + if "fast_mode" not in config: + config["fast_mode"] = {} + config["fast_mode"]["prompt_shown"] = True + self._save_gui_config(config) def set_fast_mode_enabled(self, enabled): config = self._load_gui_config() @@ -5357,6 +5357,7 @@ class Settings(Page): ("Create/Edit", self.show_registrations_page), ("Verification", self.show_verification_page), ("Systemwide", self.show_systemwide_page), + ("Bwrap Permission", self.show_bwrap_page), ("Delete Profile", self.show_delete_page), ("Error Logs", self.show_logs_page), ("Debug Help", self.show_debug_page) @@ -6567,14 +6568,18 @@ class Settings(Page): self.systemwide_page = self.create_systemwide_page() self.content_layout.addWidget(self.systemwide_page) - self.content_layout.removeWidget(self.logs_page) - self.logs_page = self.create_logs_page() - self.content_layout.addWidget(self.logs_page) + self.content_layout.removeWidget(self.bwrap_page) + self.bwrap_page = self.create_bwrap_page() + self.content_layout.addWidget(self.bwrap_page) self.content_layout.removeWidget(self.delete_page) self.delete_page = self.create_delete_page() self.content_layout.addWidget(self.delete_page) + self.content_layout.removeWidget(self.logs_page) + self.logs_page = self.create_logs_page() + self.content_layout.addWidget(self.logs_page) + self.content_layout.removeWidget(self.debug_page) self.debug_page = self.create_debug_page() self.content_layout.addWidget(self.debug_page) @@ -6772,6 +6777,7 @@ class Settings(Page): self.registrations_page = self.create_registrations_page() self.verification_page = self.create_verification_page() self.systemwide_page = self.create_systemwide_page() + self.bwrap_page = self.create_bwrap_page() self.logs_page = self.create_logs_page() self.delete_page = self.create_delete_page() self.debug_page = self.create_debug_page() @@ -6781,6 +6787,7 @@ class Settings(Page): self.content_layout.addWidget(self.registrations_page) self.content_layout.addWidget(self.verification_page) self.content_layout.addWidget(self.systemwide_page) + self.content_layout.addWidget(self.bwrap_page) self.content_layout.addWidget(self.logs_page) self.content_layout.addWidget(self.delete_page) self.content_layout.addWidget(self.debug_page) @@ -6808,6 +6815,10 @@ class Settings(Page): self.content_layout.setCurrentWidget(self.systemwide_page) self._select_menu_button("Systemwide") + def show_bwrap_page(self): + self.content_layout.setCurrentWidget(self.bwrap_page) + self._select_menu_button("Bwrap Permission") + def show_logs_page(self): self.content_layout.setCurrentWidget(self.logs_page) self._select_menu_button("Error Logs") @@ -6966,7 +6977,7 @@ class Settings(Page): layout.addLayout(status_layout) toggle_layout = QHBoxLayout() - self.systemwide_toggle = QCheckBox("Enable system-wide policy") + self.systemwide_toggle = QCheckBox("Enable \"No Sudo\" Systemwide Policy") self.systemwide_toggle.setStyleSheet(self.get_checkbox_style()) toggle_layout.addWidget(self.systemwide_toggle) toggle_layout.addStretch() @@ -6987,6 +6998,53 @@ class Settings(Page): self.load_systemwide_settings() return page + def create_bwrap_page(self): + page = QWidget() + layout = QVBoxLayout(page) + layout.setSpacing(20) + layout.setContentsMargins(20, 20, 20, 20) + + title = QLabel("BWRAP PERMISSION") + title.setStyleSheet(f"color: #808080; font-size: 12px; font-weight: bold; {self.font_style}") + layout.addWidget(title) + + description = QLabel("Control whether HydraVeil configures a capability policy so bwrap can be used without requiring additional permissions.") + 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(f"color: white; font-size: 14px; {self.font_style}") + self.bwrap_status_value = QLabel("") + self.bwrap_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + status_layout.addWidget(status_label) + status_layout.addWidget(self.bwrap_status_value) + status_layout.addStretch() + layout.addLayout(status_layout) + + toggle_layout = QHBoxLayout() + self.bwrap_toggle = QCheckBox("Enable capability policy") + self.bwrap_toggle.setStyleSheet(self.get_checkbox_style()) + toggle_layout.addWidget(self.bwrap_toggle) + toggle_layout.addStretch() + layout.addLayout(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_bwrap_settings) + + button_layout = QHBoxLayout() + button_layout.addWidget(save_button) + button_layout.addStretch() + layout.addLayout(button_layout) + + layout.addStretch() + self.load_bwrap_settings() + return page + def load_systemwide_settings(self): enabled = False try: @@ -7025,6 +7083,44 @@ class Settings(Page): self.systemwide_status_value.setText("Failed to update policy") self.systemwide_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + def load_bwrap_settings(self): + enabled = False + try: + capability_policy = PolicyController.get('capability') + if capability_policy is not None: + enabled = PolicyController.is_instated(capability_policy) + except Exception: + enabled = False + self.bwrap_toggle.setChecked(enabled) + if enabled: + self.bwrap_status_value.setText("Enabled") + self.bwrap_status_value.setStyleSheet(f"color: #2ecc71; font-size: 14px; {self.font_style}") + else: + self.bwrap_status_value.setText("Disabled") + self.bwrap_status_value.setStyleSheet(f"color: #e67e22; font-size: 14px; {self.font_style}") + + def save_bwrap_settings(self): + enable = self.bwrap_toggle.isChecked() + try: + capability_policy = PolicyController.get('capability') + if capability_policy is not None: + if enable: + PolicyController.instate(capability_policy) + else: + if PolicyController.is_instated(capability_policy): + PolicyController.revoke(capability_policy) + self.load_bwrap_settings() + self.update_status.update_status("Capability policy settings updated") + except CommandNotFoundError as e: + self.bwrap_status_value.setText(str(e)) + self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + except (PolicyAssignmentError, PolicyInstatementError, PolicyRevocationError) as e: + self.bwrap_status_value.setText(str(e)) + self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + except Exception: + self.bwrap_status_value.setText("Failed to update policy") + self.bwrap_status_value.setStyleSheet(f"color: red; font-size: 14px; {self.font_style}") + def load_registrations_settings(self) -> None: try: config = self.update_status._load_gui_config() @@ -8023,11 +8119,7 @@ class SystemwidePromptPage(Page): description.setWordWrap(True) description.setStyleSheet("font-size: 14px; color: cyan;") description.setText("If you're using Systemwide profiles, you may wish to enable them without having to enter the sudo password each time for convenience. This requires the sudo password to setup profiles and disable them (for security), but not to turn it on each time. You can choose to set this up now or later in the options menu.") - disclaimer = QLabel(self) - disclaimer.setGeometry(80, 230, 640, 60) - disclaimer.setWordWrap(True) - disclaimer.setStyleSheet("font-size: 12px; color: #808080;") - disclaimer.setText("As we outline in our documentation, HydraVeil uses a much more secure method than other VPNs, because it does NOT require a dameon to run 24/7 with elevated privileges. However, keep in mind that ANY reduction in password authentication from ANY VPN is loosening security for convenience.") + icon_label = QLabel(self) icon_label.setGeometry(80, 300, 64, 64) icon_pix = QPixmap(os.path.join(self.btn_path, "wireguard_system_wide.png")) diff --git a/pyproject.toml b/pyproject.toml index 816dbb9..26494e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "sp-hydra-veil-gui" -version = "1.1.8" +version = "1.1.9" authors = [ { name = "Simplified Privacy" }, ]