From 0a3a6ecd2ffd56037b51a76f20565dad905e1d18 Mon Sep 17 00:00:00 2001 From: JOhn Date: Sun, 17 May 2026 11:22:37 -0400 Subject: [PATCH] update: new error log flow --- gui/__main__.py | 83 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/gui/__main__.py b/gui/__main__.py index 79aa9b0..8520046 100755 --- a/gui/__main__.py +++ b/gui/__main__.py @@ -63,6 +63,38 @@ profile_observer = ProfileObserver() ticket_observer = TicketObserver() +def interpret_key_results(result: dict) -> str: + if not isinstance(result, dict): + return "There was an error with the format of the reply from the operation." + + valid = result.get('valid', False) + comparison = result.get('comparison', 'error') + error_msg = result.get('message', None) + + if error_msg: + if error_msg == "api_connection_issue": + return "There was a connection error with connecting to the API." + elif error_msg == "invalid_key": + return "Your original public key is in an invalid format to begin with." + else: + return "Unknown Error." + + if comparison == "same": + first_sentence = "The key you had locally matched what the server had also." + elif comparison == "different": + first_sentence = "Your local key was different than the server's key." + else: + first_sentence = "There was an error with the comparison." + + if valid: + second_sentence = "The signature now matches with the new key." + else: + second_sentence = "But the signature still does not match, even with the new key. If you prepare tickets anyway, they might not verify when used." + + final_msg = first_sentence + " " + second_sentence + return final_msg + + class TerminalWidget(QPlainTextEdit): line_appended = pyqtSignal(str) @@ -583,6 +615,11 @@ class CustomWindow(QMainWindow): self.is_tor_mode = current_connection == 'tor' self.set_toggle_state(self.is_tor_mode) + logging.info( + f"HydraVeil application opened (client version {Constants.HV_CLIENT_VERSION_NUMBER}, " + f"connection={current_connection}, tor_mode={self.is_tor_mode})" + ) + def perform_update_check(self): update_available = ClientController.can_be_updated() @@ -609,6 +646,7 @@ class CustomWindow(QMainWindow): self.update_status('Sync failed. Please try again later.') def sync(self): + logging.info("User clicked sync button") if ConfigurationController.get_connection() == 'tor': self.worker_thread = WorkerThread('SYNC_TOR') else: @@ -694,12 +732,14 @@ class CustomWindow(QMainWindow): ConfigurationController.set_connection('system') self.is_tor_mode = False self.set_toggle_state(False) + logging.info("User selected 'Regular' connection type from popup") connection_dialog.accept() def set_tor_connection(): ConfigurationController.set_connection('tor') self.is_tor_mode = True self.set_toggle_state(True) + logging.info("User selected 'Tor' connection type from popup") connection_dialog.accept() regular_btn.clicked.connect(set_regular_connection) @@ -815,6 +855,14 @@ class CustomWindow(QMainWindow): self._save_gui_config(config) def stop_gui_logging(self): + logger = logging.getLogger() + for handler in list(logger.handlers): + logger.removeHandler(handler) + try: + handler.close() + except Exception: + pass + if os.path.exists(self.gui_log_file): os.remove(self.gui_log_file) @@ -835,10 +883,15 @@ class CustomWindow(QMainWindow): file_handler.setLevel(logging.INFO) file_handler.setFormatter(formatter) + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.INFO) + stream_handler.setFormatter(formatter) + logger = logging.getLogger() logger.setLevel(logging.INFO) logger.handlers = [] logger.addHandler(file_handler) + logger.addHandler(stream_handler) if not os.path.exists(self.gui_log_file) or os.path.getsize(self.gui_log_file) == 0: logging.info("GUI logging system initialized") @@ -928,8 +981,9 @@ class CustomWindow(QMainWindow): self.animation_step = 0 self.animation_timer.start(16) self.is_tor_mode = not self.is_tor_mode - ConfigurationController.set_connection( - 'tor' if self.is_tor_mode else 'system') + new_connection = 'tor' if self.is_tor_mode else 'system' + ConfigurationController.set_connection(new_connection) + logging.info(f"User toggled connection mode to '{new_connection}'") def animate_toggle(self): TOTAL_STEPS = 5 @@ -1017,6 +1071,7 @@ class CustomWindow(QMainWindow): self.setWindowIcon(window_icon) def closeEvent(self, event=None): + logging.info("HydraVeil application closing") connected_profiles = self.connection_manager.get_connected_profiles() if connected_profiles: self._show_disconnect_confirmation(connected_profiles, event) @@ -7943,44 +7998,54 @@ class Settings(Page): self.show_account_page() def show_account_page(self): + logging.info("User navigated to Settings -> Overview") self.content_layout.setCurrentWidget(self.account_page) self._select_menu_button("Overview") def show_subscription_page(self): + logging.info("User navigated to Settings -> Subscriptions") self.content_layout.setCurrentWidget(self.subscription_page) self._select_menu_button("Subscriptions") def show_tickets_page(self): + logging.info("User navigated to Settings -> Tickets") self.content_layout.setCurrentWidget(self.tickets_page) self._select_menu_button("Tickets") self._refresh_tickets_inventory() self._refresh_ticket_recovery_controls() def show_registrations_page(self): + logging.info("User navigated to Settings -> Create/Edit") self.content_layout.setCurrentWidget(self.registrations_page) self._select_menu_button("Create/Edit") def show_verification_page(self): + logging.info("User navigated to Settings -> Verification") self.content_layout.setCurrentWidget(self.verification_page) self._select_menu_button("Verification") def show_systemwide_page(self): + logging.info("User navigated to Settings -> Legacy-Version") self.content_layout.setCurrentWidget(self.systemwide_page) self._select_menu_button("Systemwide") def show_bwrap_page(self): + logging.info("User navigated to Settings -> Bwrap Permission") self.content_layout.setCurrentWidget(self.bwrap_page) self._select_menu_button("Bwrap Permission") def show_logs_page(self): + logging.info("User navigated to Settings -> Error Logs") self.content_layout.setCurrentWidget(self.logs_page) self._select_menu_button("Error Logs") def show_delete_page(self): + logging.info("User navigated to Settings -> Delete Profile") self.content_layout.setCurrentWidget(self.delete_page) self._select_menu_button("Delete Profile") def show_debug_page(self): + logging.info("User navigated to Settings -> Debug Help") self.content_layout.setCurrentWidget(self.debug_page) self._select_menu_button("Debug Help") @@ -8173,6 +8238,7 @@ class Settings(Page): return failure def evaluate_ticket_public_key(self): + logging.info("User clicked 'Evaluate Public Key' button") failure = self._get_ticket_failure_for_action() if failure is None: return @@ -8190,12 +8256,15 @@ class Settings(Page): self.ticket_recovery_worker.start() def on_failed_verification_evaluated(self, result): - self._write_ticket_recovery_output(self._format_ticket_recovery_result("evaluation_results", result)) + message = interpret_key_results(result) + self._write_ticket_recovery_output(message) + logging.info(f"Public key evaluation result: {message}") self.update_status.update_status("Ticket public key evaluation complete.") self._set_ticket_recovery_busy(False) self._refresh_ticket_recovery_controls() def prepare_tickets_with_saved_blind_signatures(self): + logging.info("User clicked 'Prepare Tickets even if validation of the server's signature failed' button") failure = self._get_ticket_failure_for_action() if failure is None: return @@ -8232,26 +8301,32 @@ class Settings(Page): self._refresh_ticket_recovery_controls() def on_ticket_recovery_error(self, msg): + logging.error(f"Ticket recovery error: {msg}") self._write_ticket_recovery_output(f"EXCEPTION: {msg}") self.update_status.update_status(f"Ticket recovery error: {msg}") self._set_ticket_recovery_busy(False) self._refresh_ticket_recovery_controls() def _on_random_toggle(self, checked): + logging.info(f"User toggled random ticket setting to {'on' if checked else 'off'}") try: result = modify_random_tickets_setting('on' if checked else 'off', ticket_observer) if not (isinstance(result, dict) and result.get('valid')): msg = result.get('message', 'failed') if isinstance(result, dict) else 'failed' + logging.error(f"Could not change random ticket setting: {msg}") self.update_status.update_status(f'Could not change setting: {msg}') except Exception as e: + logging.error(f"Exception changing random ticket setting: {e}") self.update_status.update_status(f'Could not change setting: {e}') def _refresh_tickets_inventory(self): if not hasattr(self, 'tickets_inventory_label'): return + logging.info("Refreshing tickets inventory") try: unused = get_unused_tickets(ticket_observer) except Exception as e: + logging.error(f"Error fetching unused tickets: {e}") self.tickets_inventory_label.setText(f"Error: {e}") return if isinstance(unused, dict) and unused.get('valid'): @@ -8334,7 +8409,9 @@ class Settings(Page): if self.enable_gui_logging.isChecked(): self.update_status._setup_gui_logging() + logging.info("User enabled GUI logging") else: + logging.info("User disabled GUI logging") self.update_status.stop_gui_logging() self.update_status.update_status(