feat: show seed fingerprint on each screen

This commit is contained in:
thePR0M3TH3AN
2025-07-06 08:10:12 -04:00
parent 34a7775fec
commit 512a92a65b
4 changed files with 60 additions and 27 deletions

View File

@@ -20,7 +20,13 @@ from nostr.client import NostrClient
from password_manager.entry_types import EntryType
from constants import INACTIVITY_TIMEOUT, initialize_app
from utils.password_prompt import PasswordPromptError
from utils import timed_input, copy_to_clipboard, clear_screen, pause
from utils import (
timed_input,
copy_to_clipboard,
clear_screen,
pause,
clear_and_print_fingerprint,
)
from local_bip85.bip85 import Bip85Error
@@ -571,7 +577,9 @@ def handle_toggle_secret_mode(pm: PasswordManager) -> None:
def handle_profiles_menu(password_manager: PasswordManager) -> None:
"""Submenu for managing seed profiles."""
while True:
clear_screen()
clear_and_print_fingerprint(
getattr(password_manager, "current_fingerprint", None)
)
print(color_text("\nProfiles:", "menu"))
print(color_text("1. Switch Seed Profile", "menu"))
print(color_text("2. Add a New Seed Profile", "menu"))
@@ -607,7 +615,9 @@ def handle_nostr_menu(password_manager: PasswordManager) -> None:
return
while True:
clear_screen()
clear_and_print_fingerprint(
getattr(password_manager, "current_fingerprint", None)
)
print(color_text("\nNostr Settings:", "menu"))
print(color_text("1. Backup to Nostr", "menu"))
print(color_text("2. Restore from Nostr", "menu"))
@@ -641,7 +651,9 @@ def handle_nostr_menu(password_manager: PasswordManager) -> None:
def handle_settings(password_manager: PasswordManager) -> None:
"""Interactive settings menu with submenus for profiles and Nostr."""
while True:
clear_screen()
clear_and_print_fingerprint(
getattr(password_manager, "current_fingerprint", None)
)
print(color_text("\nSettings:", "menu"))
print(color_text("1. Profiles", "menu"))
print(color_text("2. Nostr", "menu"))
@@ -733,7 +745,9 @@ def display_menu(
display_fn()
pause()
while True:
clear_screen()
clear_and_print_fingerprint(
getattr(password_manager, "current_fingerprint", None)
)
if time.time() - password_manager.last_activity > inactivity_timeout:
print(colored("Session timed out. Vault locked.", "yellow"))
password_manager.lock_vault()
@@ -805,7 +819,9 @@ def display_menu(
elif choice == "2":
password_manager.update_activity()
password_manager.handle_retrieve_entry()
clear_screen()
clear_and_print_fingerprint(
getattr(password_manager, "current_fingerprint", None)
)
elif choice == "3":
password_manager.update_activity()
password_manager.handle_search_entries()

View File

@@ -52,7 +52,11 @@ from utils.password_prompt import (
)
from utils.memory_protection import InMemorySecret
from utils.clipboard import copy_to_clipboard
from utils.terminal_utils import clear_screen, pause
from utils.terminal_utils import (
clear_screen,
pause,
clear_and_print_fingerprint,
)
from constants import MIN_HEALTHY_RELAYS
from constants import (
@@ -886,7 +890,7 @@ class PasswordManager:
def handle_add_password(self) -> None:
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
website_name = input("Enter the label or website name: ").strip()
if not website_name:
print(colored("Error: Label cannot be empty.", "red"))
@@ -973,7 +977,7 @@ class PasswordManager:
def handle_add_totp(self) -> None:
"""Add a TOTP entry either derived from the seed or imported."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
while True:
print("\nAdd TOTP:")
print("1. Make 2FA (derive from seed)")
@@ -1073,7 +1077,7 @@ class PasswordManager:
def handle_add_ssh_key(self) -> None:
"""Add an SSH key pair entry and display the derived keys."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
label = input("Label: ").strip()
if not label:
print(colored("Error: Label cannot be empty.", "red"))
@@ -1115,7 +1119,7 @@ class PasswordManager:
def handle_add_seed(self) -> None:
"""Add a derived BIP-39 seed phrase entry."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
label = input("Label: ").strip()
if not label:
print(colored("Error: Label cannot be empty.", "red"))
@@ -1171,7 +1175,7 @@ class PasswordManager:
def handle_add_pgp(self) -> None:
"""Add a PGP key entry and display the generated key."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
label = input("Label: ").strip()
if not label:
print(colored("Error: Label cannot be empty.", "red"))
@@ -1224,7 +1228,7 @@ class PasswordManager:
def handle_add_nostr_key(self) -> None:
"""Add a Nostr key entry and display the derived keys."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
label = input("Label: ").strip()
if not label:
print(colored("Error: Label cannot be empty.", "red"))
@@ -1291,7 +1295,7 @@ class PasswordManager:
and displaying the corresponding password and associated details.
"""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
index_input = input(
"Enter the index number of the entry to retrieve: "
).strip()
@@ -1609,7 +1613,7 @@ class PasswordManager:
and new details to update.
"""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
index_input = input(
"Enter the index number of the entry to modify: "
).strip()
@@ -1847,7 +1851,7 @@ class PasswordManager:
def handle_search_entries(self) -> None:
"""Prompt for a query, list matches and optionally show details."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
query = input("Enter search string: ").strip()
if not query:
print(colored("No search string provided.", "yellow"))
@@ -1861,7 +1865,7 @@ class PasswordManager:
return
while True:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
print(colored("\n[+] Search Results:\n", "green"))
for idx, label, username, _url, _b in results:
display_label = label
@@ -1968,7 +1972,7 @@ class PasswordManager:
"""List entries and optionally show details."""
try:
while True:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
print(color_text("\nList Entries:", "menu"))
print(color_text("1. All", "menu"))
print(color_text("2. Passwords", "menu"))
@@ -2002,7 +2006,9 @@ class PasswordManager:
if not summaries:
continue
while True:
clear_screen()
clear_and_print_fingerprint(
getattr(self, "current_fingerprint", None)
)
print(colored("\n[+] Entries:\n", "green"))
for idx, etype, label in summaries:
if filter_kind is None:
@@ -2082,7 +2088,7 @@ class PasswordManager:
totp_list.sort(key=lambda t: t[0].lower())
print(colored("Press 'b' then Enter to return to the menu.", "cyan"))
while True:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
print(colored("Press 'b' then Enter to return to the menu.", "cyan"))
generated = [t for t in totp_list if not t[3]]
imported_list = [t for t in totp_list if t[3]]
@@ -2137,7 +2143,7 @@ class PasswordManager:
Handles verifying the script's checksum against the stored checksum to ensure integrity.
"""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
current_checksum = calculate_checksum(__file__)
try:
verified = verify_checksum(current_checksum, SCRIPT_CHECKSUM_FILE)
@@ -2172,7 +2178,7 @@ class PasswordManager:
print(colored("Operation cancelled.", "yellow"))
return
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
script_path = Path(__file__).resolve()
if update_checksum_file(str(script_path), str(SCRIPT_CHECKSUM_FILE)):
print(
@@ -2282,7 +2288,7 @@ class PasswordManager:
) -> Path | None:
"""Export the current database to an encrypted portable file."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
path = export_backup(
self.vault,
self.backup_manager,
@@ -2299,7 +2305,7 @@ class PasswordManager:
def handle_import_database(self, src: Path) -> None:
"""Import a portable database file, replacing the current index."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
import_backup(
self.vault,
self.backup_manager,
@@ -2314,7 +2320,7 @@ class PasswordManager:
def handle_export_totp_codes(self) -> Path | None:
"""Export all 2FA codes to a JSON file for other authenticator apps."""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
data = self.entry_manager.vault.load_index()
entries = data.get("entries", {})
@@ -2374,7 +2380,7 @@ class PasswordManager:
Handles the backup and reveal of the parent seed.
"""
try:
clear_screen()
clear_and_print_fingerprint(getattr(self, "current_fingerprint", None))
print(colored("\n=== Backup Parent Seed ===", "yellow"))
print(
colored(

View File

@@ -28,7 +28,7 @@ try:
from .input_utils import timed_input
from .memory_protection import InMemorySecret
from .clipboard import copy_to_clipboard
from .terminal_utils import clear_screen, pause
from .terminal_utils import clear_screen, pause, clear_and_print_fingerprint
if logger.isEnabledFor(logging.DEBUG):
logger.info("Modules imported successfully.")
@@ -57,5 +57,6 @@ __all__ = [
"InMemorySecret",
"copy_to_clipboard",
"clear_screen",
"clear_and_print_fingerprint",
"pause",
]

View File

@@ -3,11 +3,21 @@
import sys
from termcolor import colored
def clear_screen() -> None:
"""Clear the terminal screen using an ANSI escape code."""
print("\033c", end="")
def clear_and_print_fingerprint(fingerprint: str | None) -> None:
"""Clear the screen and optionally display the current fingerprint."""
clear_screen()
if fingerprint:
print(colored(f"Seed Profile: {fingerprint}", "green"))
def pause(message: str = "Press Enter to continue...") -> None:
"""Wait for the user to press Enter before proceeding."""
if not sys.stdin or not sys.stdin.isatty():