From b2a014e5b8f9789c873ee798f9c47121fed83c95 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Fri, 4 Jul 2025 19:24:55 -0400 Subject: [PATCH] Show custom fields on retrieval --- src/password_manager/manager.py | 30 ++++++++++++++ src/tests/test_custom_fields_display.py | 53 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 src/tests/test_custom_fields_display.py diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index e214698..9f0ebc4 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -1394,6 +1394,36 @@ class PasswordManager: "cyan", ) ) + custom_fields = entry.get("custom_fields", []) + if custom_fields: + print(colored("Additional Fields:", "cyan")) + hidden_fields = [] + for field in custom_fields: + label = field.get("label", "") + value = field.get("value", "") + if field.get("is_hidden"): + hidden_fields.append((label, value)) + print(colored(f" {label}: [hidden]", "cyan")) + else: + print(colored(f" {label}: {value}", "cyan")) + if hidden_fields: + show = ( + input("Reveal hidden fields? (y/N): ").strip().lower() + ) + if show == "y": + for label, value in hidden_fields: + if self.secret_mode_enabled: + copy_to_clipboard( + value, self.clipboard_clear_delay + ) + print( + colored( + f"[+] {label} copied to clipboard. Will clear in {self.clipboard_clear_delay} seconds.", + "green", + ) + ) + else: + print(colored(f" {label}: {value}", "cyan")) else: print(colored("Error: Failed to retrieve the password.", "red")) except Exception as e: diff --git a/src/tests/test_custom_fields_display.py b/src/tests/test_custom_fields_display.py new file mode 100644 index 0000000..f8966fc --- /dev/null +++ b/src/tests/test_custom_fields_display.py @@ -0,0 +1,53 @@ +import sys +from pathlib import Path +from tempfile import TemporaryDirectory +from types import SimpleNamespace + +from helpers import create_vault, TEST_SEED, TEST_PASSWORD + +sys.path.append(str(Path(__file__).resolve().parents[1])) + +from password_manager.entry_management import EntryManager +from password_manager.backup import BackupManager +from password_manager.manager import PasswordManager, EncryptionMode +from password_manager.config_manager import ConfigManager + + +def test_retrieve_entry_shows_custom_fields(monkeypatch, capsys): + with TemporaryDirectory() as tmpdir: + tmp_path = Path(tmpdir) + vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD) + cfg_mgr = ConfigManager(vault, tmp_path) + backup_mgr = BackupManager(tmp_path, cfg_mgr) + entry_mgr = EntryManager(vault, backup_mgr) + + pm = PasswordManager.__new__(PasswordManager) + pm.encryption_mode = EncryptionMode.SEED_ONLY + pm.encryption_manager = enc_mgr + pm.vault = vault + pm.entry_manager = entry_mgr + pm.backup_manager = backup_mgr + pm.password_generator = SimpleNamespace(generate_password=lambda l, i: "pw") + pm.parent_seed = TEST_SEED + pm.nostr_client = SimpleNamespace() + pm.fingerprint_dir = tmp_path + pm.secret_mode_enabled = False + + entry_mgr.add_entry( + "example", + 8, + custom_fields=[ + {"label": "visible", "value": "shown", "is_hidden": False}, + {"label": "token", "value": "secret", "is_hidden": True}, + ], + ) + + inputs = iter(["0", "y"]) + monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs)) + + pm.handle_retrieve_entry() + out = capsys.readouterr().out + assert "Additional Fields:" in out + assert "visible: shown" in out + assert "token" in out + assert "secret" in out