Merge pull request #360 from PR0M3TH3AN/codex/add-option-to-view-archived-entry-details

Enable viewing archived entry details
This commit is contained in:
thePR0M3TH3AN
2025-07-07 14:34:37 -04:00
committed by GitHub
3 changed files with 68 additions and 16 deletions

View File

@@ -257,7 +257,7 @@ When choosing **Add Entry**, you can now select **Password**, **2FA (TOTP)**,
2. SeedPass will show the current label, period, digit count, and archived status. 2. SeedPass will show the current label, period, digit count, and archived status.
3. Enter new values or press **Enter** to keep the existing settings. 3. Enter new values or press **Enter** to keep the existing settings.
4. The updated entry is saved back to your encrypted vault. 4. The updated entry is saved back to your encrypted vault.
5. Archived entries are hidden from lists but can be restored from the **List Archived** menu. 5. Archived entries are hidden from lists but can be viewed or restored from the **List Archived** menu.
### Using Secret Mode ### Using Secret Mode

View File

@@ -2157,7 +2157,7 @@ class PasswordManager:
print(colored(f"Error: Failed to archive entry: {e}", "red")) print(colored(f"Error: Failed to archive entry: {e}", "red"))
def handle_view_archived_entries(self) -> None: def handle_view_archived_entries(self) -> None:
"""Display archived entries and optionally restore one.""" """Display archived entries and optionally view or restore them."""
try: try:
archived = self.entry_manager.list_entries(include_archived=True) archived = self.entry_manager.list_entries(include_archived=True)
archived = [e for e in archived if e[4]] archived = [e for e in archived if e[4]]
@@ -2171,26 +2171,45 @@ class PasswordManager:
"Main Menu > Archived Entries", "Main Menu > Archived Entries",
) )
print(colored("\n[+] Archived Entries:\n", "green")) print(colored("\n[+] Archived Entries:\n", "green"))
for idx, label, username, url, _ in archived: for idx, label, _username, _url, _ in archived:
print(colored(f"{idx}. {label}", "cyan")) print(colored(f"{idx}. {label}", "cyan"))
idx_input = input( idx_input = input(
"Enter index to restore or press Enter to go back: " "Enter index to manage or press Enter to go back: "
).strip() ).strip()
if not idx_input: if not idx_input:
break break
if not idx_input.isdigit(): if not idx_input.isdigit() or int(idx_input) not in [
e[0] for e in archived
]:
print(colored("Invalid index.", "red")) print(colored("Invalid index.", "red"))
continue continue
restore_index = int(idx_input) entry_index = int(idx_input)
self.entry_manager.restore_entry(restore_index) while True:
action = (
input(
"Enter 'v' to view details, 'r' to restore, or press Enter to go back: "
)
.strip()
.lower()
)
if action == "v":
self.display_entry_details(entry_index)
pause()
elif action == "r":
self.entry_manager.restore_entry(entry_index)
self.is_dirty = True self.is_dirty = True
self.last_update = time.time() self.last_update = time.time()
pause() pause()
archived = [e for e in archived if e[0] != restore_index] archived = [e for e in archived if e[0] != entry_index]
if not archived: if not archived:
print(colored("All entries restored.", "green")) print(colored("All entries restored.", "green"))
pause() pause()
return
break break
elif not action:
break
else:
print(colored("Invalid choice.", "red"))
except Exception as e: except Exception as e:
logging.error(f"Error viewing archived entries: {e}", exc_info=True) logging.error(f"Error viewing archived entries: {e}", exc_info=True)
print(colored(f"Error: Failed to view archived entries: {e}", "red")) print(colored(f"Error: Failed to view archived entries: {e}", "red"))

View File

@@ -74,7 +74,40 @@ def test_view_archived_entries_cli(monkeypatch):
pm.handle_archive_entry() pm.handle_archive_entry()
assert entry_mgr.retrieve_entry(idx)["archived"] is True assert entry_mgr.retrieve_entry(idx)["archived"] is True
inputs = iter([str(idx), ""]) inputs = iter([str(idx), "r", "", ""])
monkeypatch.setattr("builtins.input", lambda *_: next(inputs)) monkeypatch.setattr("builtins.input", lambda *_: next(inputs))
pm.handle_view_archived_entries() pm.handle_view_archived_entries()
assert entry_mgr.retrieve_entry(idx)["archived"] is False assert entry_mgr.retrieve_entry(idx)["archived"] is False
def test_view_archived_entries_view_only(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.parent_seed = TEST_SEED
pm.nostr_client = SimpleNamespace()
pm.fingerprint_dir = tmp_path
pm.is_dirty = False
idx = entry_mgr.add_entry("example.com", 8)
monkeypatch.setattr("builtins.input", lambda *_: str(idx))
pm.handle_archive_entry()
assert entry_mgr.retrieve_entry(idx)["archived"] is True
inputs = iter([str(idx), "v", "", "", ""])
monkeypatch.setattr("builtins.input", lambda *_: next(inputs))
pm.handle_view_archived_entries()
assert entry_mgr.retrieve_entry(idx)["archived"] is True
out = capsys.readouterr().out
assert "example.com" in out