Merge pull request #347 from PR0M3TH3AN/codex/add-archived-flag-to-entry-management

Add archived flag to password entries
This commit is contained in:
thePR0M3TH3AN
2025-07-07 10:18:16 -04:00
committed by GitHub
8 changed files with 56 additions and 23 deletions

View File

@@ -72,6 +72,9 @@ class EntryManager:
and entry.get("type") == EntryType.PASSWORD.value
):
entry.pop("website", None)
if "archived" not in entry and "blacklisted" in entry:
entry["archived"] = entry["blacklisted"]
entry.pop("blacklisted", None)
logger.debug("Index loaded successfully.")
return data
except Exception as e:
@@ -117,7 +120,7 @@ class EntryManager:
length: int,
username: Optional[str] = None,
url: Optional[str] = None,
blacklisted: bool = False,
archived: bool = False,
notes: str = "",
custom_fields: List[Dict[str, Any]] | None = None,
) -> int:
@@ -128,7 +131,7 @@ class EntryManager:
:param length: The desired length of the password.
:param username: (Optional) The username associated with the website.
:param url: (Optional) The URL of the website.
:param blacklisted: (Optional) Whether the password is blacklisted. Defaults to False.
:param archived: (Optional) Whether the entry is archived. Defaults to False.
:param notes: (Optional) Extra notes to attach to the entry.
:return: The assigned index of the new entry.
"""
@@ -142,7 +145,7 @@ class EntryManager:
"length": length,
"username": username if username else "",
"url": url if url else "",
"blacklisted": blacklisted,
"archived": archived,
"type": EntryType.PASSWORD.value,
"kind": EntryType.PASSWORD.value,
"notes": notes,
@@ -184,6 +187,7 @@ class EntryManager:
label: str,
parent_seed: str,
*,
archived: bool = False,
secret: str | None = None,
index: int | None = None,
period: int = 30,
@@ -205,6 +209,7 @@ class EntryManager:
"index": index,
"period": period,
"digits": digits,
"archived": archived,
}
else:
entry = {
@@ -214,6 +219,7 @@ class EntryManager:
"secret": secret,
"period": period,
"digits": digits,
"archived": archived,
}
data["entries"][str(entry_id)] = entry
@@ -234,6 +240,7 @@ class EntryManager:
parent_seed: str,
index: int | None = None,
notes: str = "",
archived: bool = False,
) -> int:
"""Add a new SSH key pair entry.
@@ -253,6 +260,7 @@ class EntryManager:
"index": index,
"label": label,
"notes": notes,
"archived": archived,
}
self._save_index(data)
self.update_checksum()
@@ -281,6 +289,7 @@ class EntryManager:
key_type: str = "ed25519",
user_id: str = "",
notes: str = "",
archived: bool = False,
) -> int:
"""Add a new PGP key entry."""
@@ -297,6 +306,7 @@ class EntryManager:
"key_type": key_type,
"user_id": user_id,
"notes": notes,
"archived": archived,
}
self._save_index(data)
self.update_checksum()
@@ -329,6 +339,7 @@ class EntryManager:
label: str,
index: int | None = None,
notes: str = "",
archived: bool = False,
) -> int:
"""Add a new Nostr key pair entry."""
@@ -343,6 +354,7 @@ class EntryManager:
"index": index,
"label": label,
"notes": notes,
"archived": archived,
}
self._save_index(data)
self.update_checksum()
@@ -381,6 +393,7 @@ class EntryManager:
index: int | None = None,
words_num: int = 24,
notes: str = "",
archived: bool = False,
) -> int:
"""Add a new derived seed phrase entry."""
@@ -396,6 +409,7 @@ class EntryManager:
"label": label,
"words": words_num,
"notes": notes,
"archived": archived,
}
self._save_index(data)
self.update_checksum()
@@ -505,13 +519,14 @@ class EntryManager:
index: int,
username: Optional[str] = None,
url: Optional[str] = None,
blacklisted: Optional[bool] = None,
archived: Optional[bool] = None,
notes: Optional[str] = None,
*,
label: Optional[str] = None,
period: Optional[int] = None,
digits: Optional[int] = None,
custom_fields: List[Dict[str, Any]] | None = None,
**legacy,
) -> None:
"""
Modifies an existing entry based on the provided index and new values.
@@ -519,7 +534,7 @@ class EntryManager:
:param index: The index number of the entry to modify.
:param username: (Optional) The new username (password entries).
:param url: (Optional) The new URL (password entries).
:param blacklisted: (Optional) The new blacklist status.
:param archived: (Optional) The new archived status.
:param notes: (Optional) New notes to attach to the entry.
:param label: (Optional) The new label for the entry.
:param period: (Optional) The new TOTP period in seconds.
@@ -564,10 +579,15 @@ class EntryManager:
entry["url"] = url
logger.debug(f"Updated URL to '{url}' for index {index}.")
if blacklisted is not None:
entry["blacklisted"] = blacklisted
if archived is None and "blacklisted" in legacy:
archived = legacy["blacklisted"]
if archived is not None:
entry["archived"] = archived
if "blacklisted" in entry:
entry.pop("blacklisted", None)
logger.debug(
f"Updated blacklist status to '{blacklisted}' for index {index}."
f"Updated archived status to '{archived}' for index {index}."
)
if notes is not None:
@@ -598,6 +618,14 @@ class EntryManager:
colored(f"Error: Failed to modify entry at index {index}: {e}", "red")
)
def archive_entry(self, index: int) -> None:
"""Mark the specified entry as archived."""
self.modify_entry(index, archived=True)
def restore_entry(self, index: int) -> None:
"""Unarchive the specified entry."""
self.modify_entry(index, archived=False)
def list_entries(
self, sort_by: str = "index", filter_kind: str | None = None
) -> List[Tuple[int, str, Optional[str], Optional[str], bool]]:
@@ -644,7 +672,7 @@ class EntryManager:
label,
entry.get("username", ""),
entry.get("url", ""),
entry.get("blacklisted", False),
entry.get("archived", entry.get("blacklisted", False)),
)
)
else:
@@ -677,7 +705,7 @@ class EntryManager:
print(colored(f" URL: {entry.get('url') or 'N/A'}", "cyan"))
print(
colored(
f" Blacklisted: {'Yes' if entry.get('blacklisted', False) else 'No'}",
f" Blacklisted: {'Yes' if entry.get('archived', entry.get('blacklisted', False)) else 'No'}",
"cyan",
)
)
@@ -739,7 +767,7 @@ class EntryManager:
label,
username,
url,
entry.get("blacklisted", False),
entry.get("archived", entry.get("blacklisted", False)),
)
)
else:

View File

@@ -939,7 +939,7 @@ class PasswordManager:
length,
username,
url,
blacklisted=False,
archived=False,
notes=notes,
custom_fields=custom_fields,
)
@@ -1545,7 +1545,7 @@ class PasswordManager:
length = entry.get("length")
username = entry.get("username")
url = entry.get("url")
blacklisted = entry.get("blacklisted")
blacklisted = entry.get("archived", entry.get("blacklisted"))
notes = entry.get("notes", "")
print(
@@ -1660,7 +1660,7 @@ class PasswordManager:
label = entry.get("label", "")
period = int(entry.get("period", 30))
digits = int(entry.get("digits", 6))
blacklisted = entry.get("blacklisted", False)
blacklisted = entry.get("archived", entry.get("blacklisted", False))
notes = entry.get("notes", "")
print(
@@ -1751,7 +1751,7 @@ class PasswordManager:
self.entry_manager.modify_entry(
index,
blacklisted=new_blacklisted,
archived=new_blacklisted,
notes=new_notes,
label=new_label,
period=new_period,
@@ -1762,7 +1762,7 @@ class PasswordManager:
website_name = entry.get("label", entry.get("website"))
username = entry.get("username")
url = entry.get("url")
blacklisted = entry.get("blacklisted")
blacklisted = entry.get("archived", entry.get("blacklisted"))
notes = entry.get("notes", "")
print(
@@ -1847,8 +1847,8 @@ class PasswordManager:
index,
new_username,
new_url,
new_blacklisted,
new_notes,
archived=new_blacklisted,
notes=new_notes,
label=new_label,
custom_fields=custom_fields,
)
@@ -1992,7 +1992,7 @@ class PasswordManager:
website = entry.get("label", entry.get("website", ""))
username = entry.get("username", "")
url = entry.get("url", "")
blacklisted = entry.get("blacklisted", False)
blacklisted = entry.get("archived", entry.get("blacklisted", False))
print(color_text(f" Label: {website}", "index"))
print(color_text(f" Username: {username or 'N/A'}", "index"))
print(color_text(f" URL: {url or 'N/A'}", "index"))
@@ -2115,7 +2115,7 @@ class PasswordManager:
totp_list: list[tuple[str, int, int, bool]] = []
for idx_str, entry in entries.items():
if entry.get("type") == EntryType.TOTP.value and not entry.get(
"blacklisted", False
"archived", entry.get("blacklisted", False)
):
label = entry.get("label", "")
period = int(entry.get("period", 30))

View File

@@ -34,7 +34,7 @@ def test_add_and_retrieve_entry():
"length": 12,
"username": "user",
"url": "",
"blacklisted": False,
"archived": False,
"type": "password",
"kind": "password",
"notes": "",

View File

@@ -63,5 +63,6 @@ def test_handle_add_totp(monkeypatch, capsys):
"index": 0,
"period": 30,
"digits": 6,
"archived": False,
}
assert "ID 0" in out

View File

@@ -61,7 +61,7 @@ def test_handle_display_totp_codes(monkeypatch, capsys):
assert "123456" in out
def test_display_totp_codes_excludes_blacklisted(monkeypatch, capsys):
def test_display_totp_codes_excludes_archived(monkeypatch, capsys):
with TemporaryDirectory() as tmpdir:
tmp_path = Path(tmpdir)
vault, enc_mgr = create_vault(tmp_path, TEST_SEED, TEST_PASSWORD)
@@ -83,7 +83,7 @@ def test_display_totp_codes_excludes_blacklisted(monkeypatch, capsys):
entry_mgr.add_totp("Visible", TEST_SEED)
entry_mgr.add_totp("Hidden", TEST_SEED)
entry_mgr.modify_entry(1, blacklisted=True)
entry_mgr.modify_entry(1, archived=True)
monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456")
monkeypatch.setattr(

View File

@@ -30,6 +30,7 @@ def test_nostr_key_determinism():
"index": idx,
"label": "main",
"notes": "",
"archived": False,
}
npub1, nsec1 = entry_mgr.get_nostr_key_pair(idx, TEST_SEED)

View File

@@ -28,6 +28,7 @@ def test_add_and_retrieve_ssh_key_pair():
"index": index,
"label": "ssh",
"notes": "",
"archived": False,
}
priv1, pub1 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)

View File

@@ -35,6 +35,7 @@ def test_add_totp_and_get_code():
"index": 0,
"period": 30,
"digits": 6,
"archived": False,
}
code = entry_mgr.get_totp_code(0, TEST_SEED, timestamp=0)
@@ -72,6 +73,7 @@ def test_add_totp_imported(tmp_path):
"secret": secret,
"period": 30,
"digits": 6,
"archived": False,
}
code = em.get_totp_code(0, timestamp=0)
assert code == pyotp.TOTP(secret).at(0)