Display and edit entry tags

This commit is contained in:
thePR0M3TH3AN
2025-07-08 16:45:08 -04:00
parent eda9182d44
commit ef66464317
2 changed files with 107 additions and 9 deletions

View File

@@ -1623,7 +1623,7 @@ class PasswordManager:
print(colored("C. Add Custom Field", "cyan")) print(colored("C. Add Custom Field", "cyan"))
print(colored("H. Add Hidden Field", "cyan")) print(colored("H. Add Hidden Field", "cyan"))
print(colored("E. Edit", "cyan")) print(colored("E. Edit", "cyan"))
print(colored("T. Add Tags", "cyan")) print(colored("T. Edit Tags", "cyan"))
print(colored("Q. Show QR codes", "cyan")) print(colored("Q. Show QR codes", "cyan"))
choice = ( choice = (
@@ -1662,11 +1662,21 @@ class PasswordManager:
self.is_dirty = True self.is_dirty = True
self.last_update = time.time() self.last_update = time.time()
elif choice == "t": elif choice == "t":
tags_input = input("Enter tags (comma-separated): ").strip() current_tags = entry.get("tags", [])
if tags_input: print(
new_tags = [t.strip() for t in tags_input.split(",") if t.strip()] colored(
existing_tags = entry.get("tags", []) f"Current tags: {', '.join(current_tags) if current_tags else 'None'}",
tags = list({*existing_tags, *new_tags}) "cyan",
)
)
tags_input = input(
"Enter tags (comma-separated, leave blank to remove all tags): "
).strip()
tags = (
[t.strip() for t in tags_input.split(",") if t.strip()]
if tags_input
else []
)
self.entry_manager.modify_entry(index, tags=tags) self.entry_manager.modify_entry(index, tags=tags)
self.is_dirty = True self.is_dirty = True
self.last_update = time.time() self.last_update = time.time()
@@ -1836,6 +1846,9 @@ class PasswordManager:
print(color_text(f"Code: {code}", category)) print(color_text(f"Code: {code}", category))
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
remaining = self.entry_manager.get_totp_time_remaining(index) remaining = self.entry_manager.get_totp_time_remaining(index)
exit_loop = False exit_loop = False
while remaining > 0: while remaining > 0:
@@ -1885,6 +1898,9 @@ class PasswordManager:
print(colored(f"Label: {label}", "cyan")) print(colored(f"Label: {label}", "cyan"))
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
print(colored("Public Key:", "cyan")) print(colored("Public Key:", "cyan"))
print(color_text(pub_pem, "default")) print(color_text(pub_pem, "default"))
if self.secret_mode_enabled: if self.secret_mode_enabled:
@@ -1920,6 +1936,9 @@ class PasswordManager:
print(colored(f"Label: {label}", "cyan")) print(colored(f"Label: {label}", "cyan"))
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
if self.secret_mode_enabled: if self.secret_mode_enabled:
copy_to_clipboard(phrase, self.clipboard_clear_delay) copy_to_clipboard(phrase, self.clipboard_clear_delay)
print( print(
@@ -1969,6 +1988,9 @@ class PasswordManager:
print(colored(f"User ID: {label}", "cyan")) print(colored(f"User ID: {label}", "cyan"))
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
print(colored(f"Fingerprint: {fingerprint}", "cyan")) print(colored(f"Fingerprint: {fingerprint}", "cyan"))
if self.secret_mode_enabled: if self.secret_mode_enabled:
copy_to_clipboard(priv_key, self.clipboard_clear_delay) copy_to_clipboard(priv_key, self.clipboard_clear_delay)
@@ -2009,6 +2031,9 @@ class PasswordManager:
# QR code display removed for npub and nsec # QR code display removed for npub and nsec
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
except Exception as e: except Exception as e:
logging.error(f"Error deriving Nostr keys: {e}", exc_info=True) logging.error(f"Error deriving Nostr keys: {e}", exc_info=True)
print(colored(f"Error: Failed to derive Nostr keys: {e}", "red")) print(colored(f"Error: Failed to derive Nostr keys: {e}", "red"))
@@ -2024,6 +2049,9 @@ class PasswordManager:
print(colored(f"Retrieving value for '{label}'.", "cyan")) print(colored(f"Retrieving value for '{label}'.", "cyan"))
if notes: if notes:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
print( print(
colored( colored(
f"Archived Status: {'Archived' if archived else 'Active'}", f"Archived Status: {'Archived' if archived else 'Active'}",
@@ -2082,6 +2110,9 @@ class PasswordManager:
print(colored(f"Notes: {notes}", "cyan")) print(colored(f"Notes: {notes}", "cyan"))
if fingerprint: if fingerprint:
print(colored(f"Fingerprint: {fingerprint}", "cyan")) print(colored(f"Fingerprint: {fingerprint}", "cyan"))
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
print( print(
colored( colored(
f"Archived Status: {'Archived' if archived else 'Active'}", f"Archived Status: {'Archived' if archived else 'Active'}",
@@ -2172,6 +2203,9 @@ class PasswordManager:
"cyan", "cyan",
) )
) )
tags = entry.get("tags", [])
if tags:
print(colored(f"Tags: {', '.join(tags)}", "cyan"))
custom_fields = entry.get("custom_fields", []) custom_fields = entry.get("custom_fields", [])
if custom_fields: if custom_fields:
print(colored("Additional Fields:", "cyan")) print(colored("Additional Fields:", "cyan"))
@@ -2651,6 +2685,9 @@ class PasswordManager:
notes = entry.get("notes", "") notes = entry.get("notes", "")
if notes: if notes:
print(color_text(f" Notes: {notes}", "index")) print(color_text(f" Notes: {notes}", "index"))
tags = entry.get("tags", [])
if tags:
print(color_text(f" Tags: {', '.join(tags)}", "index"))
elif etype == EntryType.SEED.value: elif etype == EntryType.SEED.value:
print(color_text(" Type: Seed Phrase", "index")) print(color_text(" Type: Seed Phrase", "index"))
print(color_text(f" Label: {entry.get('label', '')}", "index")) print(color_text(f" Label: {entry.get('label', '')}", "index"))
@@ -2661,6 +2698,9 @@ class PasswordManager:
notes = entry.get("notes", "") notes = entry.get("notes", "")
if notes: if notes:
print(color_text(f" Notes: {notes}", "index")) print(color_text(f" Notes: {notes}", "index"))
tags = entry.get("tags", [])
if tags:
print(color_text(f" Tags: {', '.join(tags)}", "index"))
elif etype == EntryType.SSH.value: elif etype == EntryType.SSH.value:
print(color_text(" Type: SSH Key", "index")) print(color_text(" Type: SSH Key", "index"))
print(color_text(f" Label: {entry.get('label', '')}", "index")) print(color_text(f" Label: {entry.get('label', '')}", "index"))
@@ -2670,6 +2710,9 @@ class PasswordManager:
notes = entry.get("notes", "") notes = entry.get("notes", "")
if notes: if notes:
print(color_text(f" Notes: {notes}", "index")) print(color_text(f" Notes: {notes}", "index"))
tags = entry.get("tags", [])
if tags:
print(color_text(f" Tags: {', '.join(tags)}", "index"))
elif etype == EntryType.PGP.value: elif etype == EntryType.PGP.value:
print(color_text(" Type: PGP Key", "index")) print(color_text(" Type: PGP Key", "index"))
print(color_text(f" Label: {entry.get('label', '')}", "index")) print(color_text(f" Label: {entry.get('label', '')}", "index"))
@@ -2685,6 +2728,9 @@ class PasswordManager:
notes = entry.get("notes", "") notes = entry.get("notes", "")
if notes: if notes:
print(color_text(f" Notes: {notes}", "index")) print(color_text(f" Notes: {notes}", "index"))
tags = entry.get("tags", [])
if tags:
print(color_text(f" Tags: {', '.join(tags)}", "index"))
elif etype == EntryType.NOSTR.value: elif etype == EntryType.NOSTR.value:
print(color_text(" Type: Nostr Key", "index")) print(color_text(" Type: Nostr Key", "index"))
print(color_text(f" Label: {entry.get('label', '')}", "index")) print(color_text(f" Label: {entry.get('label', '')}", "index"))
@@ -2694,6 +2740,9 @@ class PasswordManager:
notes = entry.get("notes", "") notes = entry.get("notes", "")
if notes: if notes:
print(color_text(f" Notes: {notes}", "index")) print(color_text(f" Notes: {notes}", "index"))
tags = entry.get("tags", [])
if tags:
print(color_text(f" Tags: {', '.join(tags)}", "index"))
else: else:
website = entry.get("label", entry.get("website", "")) website = entry.get("label", entry.get("website", ""))
username = entry.get("username", "") username = entry.get("username", "")

View File

@@ -0,0 +1,49 @@
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
class FakePasswordGenerator:
def generate_password(self, length: int, index: int) -> str: # noqa: D401
return "pw"
def test_edit_tags_from_retrieve(monkeypatch):
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 = FakePasswordGenerator()
pm.parent_seed = TEST_SEED
pm.nostr_client = SimpleNamespace()
pm.fingerprint_dir = tmp_path
pm.secret_mode_enabled = False
index = entry_mgr.add_entry("example.com", 8, tags=["old"])
inputs = iter([str(index), "t", "newtag", ""])
monkeypatch.setattr("builtins.input", lambda *a, **k: next(inputs))
pm.handle_retrieve_entry()
entry = entry_mgr.retrieve_entry(index)
assert entry.get("tags", []) == ["newtag"]