From 74f5911bf78c2361aa7369d793313b225c9b07f7 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Mon, 14 Jul 2025 17:01:49 -0400 Subject: [PATCH] Use notification helper consistently --- src/main.py | 7 +--- src/password_manager/manager.py | 59 +++++++++++++++++++++++++--- src/tests/test_menu_notifications.py | 18 +++++++-- src/utils/terminal_utils.py | 8 ++-- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/main.py b/src/main.py index 4cd9993..1751c3f 100644 --- a/src/main.py +++ b/src/main.py @@ -26,7 +26,6 @@ from utils import ( clear_screen, pause, clear_header_with_notification, - clear_and_print_fingerprint, ) import queue from local_bip85.bip85 import Bip85Error @@ -949,15 +948,13 @@ def display_menu( "header_fingerprint_args", (getattr(password_manager, "current_fingerprint", None), None, None), ) - clear_and_print_fingerprint( + clear_header_with_notification( + password_manager, fp, "Main Menu", parent_fingerprint=parent_fp, child_fingerprint=child_fp, ) - note_line = get_notification_text(password_manager) - if note_line: - print(note_line) if time.time() - password_manager.last_activity > inactivity_timeout: print(colored("Session timed out. Vault locked.", "yellow")) password_manager.lock_vault() diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 846b83f..874c598 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -1178,6 +1178,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > Password", parent_fingerprint=parent_fp, @@ -1277,13 +1278,14 @@ class PasswordManager: """Add a TOTP entry either derived from the seed or imported.""" try: fp, parent_fp, child_fp = self.header_fingerprint_args - clear_header_with_notification( - fp, - "Main Menu > Add Entry > 2FA (TOTP)", - parent_fingerprint=parent_fp, - child_fingerprint=child_fp, - ) while True: + clear_header_with_notification( + self, + fp, + "Main Menu > Add Entry > 2FA (TOTP)", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) print("\nAdd TOTP:") print("1. Make 2FA (derive from seed)") print("2. Import 2FA (paste otpauth URI or secret)") @@ -1406,6 +1408,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > SSH Key", parent_fingerprint=parent_fp, @@ -1462,6 +1465,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > Seed Phrase", parent_fingerprint=parent_fp, @@ -1530,6 +1534,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > PGP Key", parent_fingerprint=parent_fp, @@ -1596,6 +1601,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > Nostr Key Pair", parent_fingerprint=parent_fp, @@ -1652,6 +1658,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > Key/Value", parent_fingerprint=parent_fp, @@ -1727,6 +1734,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Add Entry > Managed Account", parent_fingerprint=parent_fp, @@ -1823,6 +1831,14 @@ class PasswordManager: def _entry_actions_menu(self, index: int, entry: dict) -> None: """Provide actions for a retrieved entry.""" while True: + fp, parent_fp, child_fp = self.header_fingerprint_args + clear_header_with_notification( + self, + fp, + "Entry Actions", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) archived = entry.get("archived", entry.get("blacklisted", False)) entry_type = entry.get("type", EntryType.PASSWORD.value) print(colored("\n[+] Entry Actions:", "green")) @@ -1908,6 +1924,14 @@ class PasswordManager: """Sub-menu for editing common entry fields.""" entry_type = entry.get("type", EntryType.PASSWORD.value) while True: + fp, parent_fp, child_fp = self.header_fingerprint_args + clear_header_with_notification( + self, + fp, + "Edit Entry", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) print(colored("\n[+] Edit Menu:", "green")) print(colored("L. Edit Label", "cyan")) if entry_type == EntryType.PASSWORD.value: @@ -1977,6 +2001,14 @@ class PasswordManager: if entry_type == EntryType.NOSTR.value: while True: + fp, parent_fp, child_fp = self.header_fingerprint_args + clear_header_with_notification( + self, + fp, + "QR Codes", + parent_fingerprint=parent_fp, + child_fingerprint=child_fp, + ) print(colored("\n[+] QR Codes:", "green")) print(colored("P. Public key", "cyan")) print(colored("K. Private key", "cyan")) @@ -2016,6 +2048,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Retrieve Entry", parent_fingerprint=parent_fp, @@ -2467,6 +2500,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Modify Entry", parent_fingerprint=parent_fp, @@ -2821,6 +2855,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Search Entries", parent_fingerprint=parent_fp, @@ -2841,6 +2876,7 @@ class PasswordManager: while True: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Search Entries", parent_fingerprint=parent_fp, @@ -2972,6 +3008,7 @@ class PasswordManager: while True: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > List Entries", parent_fingerprint=parent_fp, @@ -3020,6 +3057,7 @@ class PasswordManager: while True: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > List Entries", parent_fingerprint=parent_fp, @@ -3112,6 +3150,7 @@ class PasswordManager: while True: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Archived Entries", parent_fingerprint=parent_fp, @@ -3169,6 +3208,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > 2FA Codes", parent_fingerprint=parent_fp, @@ -3195,6 +3235,7 @@ class PasswordManager: while True: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > 2FA Codes", parent_fingerprint=parent_fp, @@ -3256,6 +3297,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Verify Script Checksum", parent_fingerprint=parent_fp, @@ -3295,6 +3337,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Generate Script Checksum", parent_fingerprint=parent_fp, @@ -3413,6 +3456,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Export database", parent_fingerprint=parent_fp, @@ -3436,6 +3480,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Import database", parent_fingerprint=parent_fp, @@ -3458,6 +3503,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Export 2FA codes", parent_fingerprint=parent_fp, @@ -3531,6 +3577,7 @@ class PasswordManager: try: fp, parent_fp, child_fp = self.header_fingerprint_args clear_header_with_notification( + self, fp, "Main Menu > Settings > Backup Parent Seed", parent_fingerprint=parent_fp, diff --git a/src/tests/test_menu_notifications.py b/src/tests/test_menu_notifications.py index 63a43e0..95aa9be 100644 --- a/src/tests/test_menu_notifications.py +++ b/src/tests/test_menu_notifications.py @@ -16,6 +16,7 @@ def _make_pm(msg): q.put(SimpleNamespace(message=msg, level="INFO")) return SimpleNamespace( notifications=q, + get_current_notification=lambda: q.queue[-1] if not q.empty() else None, is_dirty=False, last_update=time.time(), last_activity=time.time(), @@ -40,9 +41,17 @@ def test_display_menu_prints_notifications(monkeypatch, capsys): pm = _make_pm("hello") monkeypatch.setattr(main, "_display_live_stats", lambda *_: None) monkeypatch.setattr( - main, "clear_and_print_fingerprint", lambda *a, **k: print("HEADER") + main, + "clear_header_with_notification", + lambda pm, *a, **k: ( + print("HEADER"), + print( + pm.get_current_notification().message + if pm.get_current_notification() + else "" + ), + ), ) - monkeypatch.setattr(main, "get_notification_text", lambda *_: "hello") monkeypatch.setattr(main, "timed_input", lambda *a, **k: "") with pytest.raises(SystemExit): main.display_menu(pm, sync_interval=1000, inactivity_timeout=1000) @@ -56,11 +65,12 @@ def test_display_menu_reuses_notification_line(monkeypatch, capsys): msgs = iter(["first", "second"]) monkeypatch.setattr(main, "_display_live_stats", lambda *_: None) monkeypatch.setattr( - main, "clear_and_print_fingerprint", lambda *a, **k: print("HEADER") + main, + "clear_header_with_notification", + lambda _pm, *a, **k: (print("HEADER"), print(next(msgs, ""))), ) inputs = iter(["9", ""]) monkeypatch.setattr(main, "timed_input", lambda *a, **k: next(inputs)) - monkeypatch.setattr(main, "get_notification_text", lambda _pm: next(msgs, "")) with pytest.raises(SystemExit): main.display_menu(pm, sync_interval=1000, inactivity_timeout=1000) out = capsys.readouterr().out diff --git a/src/utils/terminal_utils.py b/src/utils/terminal_utils.py index c0b370c..f1e05e7 100644 --- a/src/utils/terminal_utils.py +++ b/src/utils/terminal_utils.py @@ -80,13 +80,15 @@ def clear_header_with_notification( note = pm.get_current_notification() except Exception: note = None + + line = "" if note: category = getattr(note, "level", "info").lower() if category not in ("info", "warning", "error"): category = "info" - print(color_text(getattr(note, "message", ""), category)) - else: - print() + line = color_text(getattr(note, "message", ""), category) + + print(line) def pause(message: str = "Press Enter to continue...") -> None: