mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-09 07:48:57 +00:00
Merge pull request #400 from PR0M3TH3AN/codex/update-entry-management-for-tags-support
Add tag support for entries
This commit is contained in:
@@ -79,6 +79,7 @@ class EntryManager:
|
|||||||
if "word_count" not in entry and "words" in entry:
|
if "word_count" not in entry and "words" in entry:
|
||||||
entry["word_count"] = entry["words"]
|
entry["word_count"] = entry["words"]
|
||||||
entry.pop("words", None)
|
entry.pop("words", None)
|
||||||
|
entry.setdefault("tags", [])
|
||||||
logger.debug("Index loaded successfully.")
|
logger.debug("Index loaded successfully.")
|
||||||
return data
|
return data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -127,6 +128,7 @@ class EntryManager:
|
|||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
custom_fields: List[Dict[str, Any]] | None = None,
|
custom_fields: List[Dict[str, Any]] | None = None,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Adds a new entry to the encrypted JSON index file.
|
Adds a new entry to the encrypted JSON index file.
|
||||||
@@ -154,6 +156,7 @@ class EntryManager:
|
|||||||
"kind": EntryType.PASSWORD.value,
|
"kind": EntryType.PASSWORD.value,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"custom_fields": custom_fields or [],
|
"custom_fields": custom_fields or [],
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug(f"Added entry at index {index}: {data['entries'][str(index)]}")
|
logger.debug(f"Added entry at index {index}: {data['entries'][str(index)]}")
|
||||||
@@ -197,6 +200,7 @@ class EntryManager:
|
|||||||
period: int = 30,
|
period: int = 30,
|
||||||
digits: int = 6,
|
digits: int = 6,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Add a new TOTP entry and return the provisioning URI."""
|
"""Add a new TOTP entry and return the provisioning URI."""
|
||||||
entry_id = self.get_next_index()
|
entry_id = self.get_next_index()
|
||||||
@@ -216,6 +220,7 @@ class EntryManager:
|
|||||||
"digits": digits,
|
"digits": digits,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
entry = {
|
entry = {
|
||||||
@@ -227,6 +232,7 @@ class EntryManager:
|
|||||||
"digits": digits,
|
"digits": digits,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
|
|
||||||
data["entries"][str(entry_id)] = entry
|
data["entries"][str(entry_id)] = entry
|
||||||
@@ -248,6 +254,7 @@ class EntryManager:
|
|||||||
index: int | None = None,
|
index: int | None = None,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new SSH key pair entry.
|
"""Add a new SSH key pair entry.
|
||||||
|
|
||||||
@@ -268,6 +275,7 @@ class EntryManager:
|
|||||||
"label": label,
|
"label": label,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
self.update_checksum()
|
self.update_checksum()
|
||||||
@@ -297,6 +305,7 @@ class EntryManager:
|
|||||||
user_id: str = "",
|
user_id: str = "",
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new PGP key entry."""
|
"""Add a new PGP key entry."""
|
||||||
|
|
||||||
@@ -314,6 +323,7 @@ class EntryManager:
|
|||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
self.update_checksum()
|
self.update_checksum()
|
||||||
@@ -347,6 +357,7 @@ class EntryManager:
|
|||||||
index: int | None = None,
|
index: int | None = None,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new Nostr key pair entry."""
|
"""Add a new Nostr key pair entry."""
|
||||||
|
|
||||||
@@ -362,6 +373,7 @@ class EntryManager:
|
|||||||
"label": label,
|
"label": label,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
self.update_checksum()
|
self.update_checksum()
|
||||||
@@ -376,6 +388,7 @@ class EntryManager:
|
|||||||
notes: str = "",
|
notes: str = "",
|
||||||
custom_fields=None,
|
custom_fields=None,
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new generic key/value entry."""
|
"""Add a new generic key/value entry."""
|
||||||
|
|
||||||
@@ -391,6 +404,7 @@ class EntryManager:
|
|||||||
"notes": notes,
|
"notes": notes,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
"custom_fields": custom_fields or [],
|
"custom_fields": custom_fields or [],
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
|
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
@@ -431,6 +445,7 @@ class EntryManager:
|
|||||||
words_num: int = 24,
|
words_num: int = 24,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new derived seed phrase entry."""
|
"""Add a new derived seed phrase entry."""
|
||||||
|
|
||||||
@@ -447,6 +462,7 @@ class EntryManager:
|
|||||||
"word_count": words_num,
|
"word_count": words_num,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
self.update_checksum()
|
self.update_checksum()
|
||||||
@@ -483,6 +499,7 @@ class EntryManager:
|
|||||||
index: int | None = None,
|
index: int | None = None,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
archived: bool = False,
|
archived: bool = False,
|
||||||
|
tags: list[str] | None = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new managed account seed entry.
|
"""Add a new managed account seed entry.
|
||||||
|
|
||||||
@@ -518,6 +535,7 @@ class EntryManager:
|
|||||||
"notes": notes,
|
"notes": notes,
|
||||||
"fingerprint": fingerprint,
|
"fingerprint": fingerprint,
|
||||||
"archived": archived,
|
"archived": archived,
|
||||||
|
"tags": tags or [],
|
||||||
}
|
}
|
||||||
|
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
@@ -642,6 +660,7 @@ class EntryManager:
|
|||||||
digits: Optional[int] = None,
|
digits: Optional[int] = None,
|
||||||
value: Optional[str] = None,
|
value: Optional[str] = None,
|
||||||
custom_fields: List[Dict[str, Any]] | None = None,
|
custom_fields: List[Dict[str, Any]] | None = None,
|
||||||
|
tags: list[str] | None = None,
|
||||||
**legacy,
|
**legacy,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -727,6 +746,10 @@ class EntryManager:
|
|||||||
f"Updated custom fields for index {index}: {custom_fields}"
|
f"Updated custom fields for index {index}: {custom_fields}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if tags is not None:
|
||||||
|
entry["tags"] = tags
|
||||||
|
logger.debug(f"Updated tags for index {index}: {tags}")
|
||||||
|
|
||||||
data["entries"][str(index)] = entry
|
data["entries"][str(index)] = entry
|
||||||
logger.debug(f"Modified entry at index {index}: {entry}")
|
logger.debug(f"Modified entry at index {index}: {entry}")
|
||||||
|
|
||||||
@@ -890,8 +913,10 @@ class EntryManager:
|
|||||||
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
||||||
label = entry.get("label", entry.get("website", ""))
|
label = entry.get("label", entry.get("website", ""))
|
||||||
notes = entry.get("notes", "")
|
notes = entry.get("notes", "")
|
||||||
|
tags = entry.get("tags", [])
|
||||||
label_match = query_lower in label.lower()
|
label_match = query_lower in label.lower()
|
||||||
notes_match = query_lower in notes.lower()
|
notes_match = query_lower in notes.lower()
|
||||||
|
tags_match = any(query_lower in str(t).lower() for t in tags)
|
||||||
|
|
||||||
if etype == EntryType.PASSWORD.value:
|
if etype == EntryType.PASSWORD.value:
|
||||||
username = entry.get("username", "")
|
username = entry.get("username", "")
|
||||||
@@ -908,6 +933,7 @@ class EntryManager:
|
|||||||
or query_lower in url.lower()
|
or query_lower in url.lower()
|
||||||
or notes_match
|
or notes_match
|
||||||
or custom_match
|
or custom_match
|
||||||
|
or tags_match
|
||||||
):
|
):
|
||||||
results.append(
|
results.append(
|
||||||
(
|
(
|
||||||
@@ -931,6 +957,7 @@ class EntryManager:
|
|||||||
or query_lower in value_field.lower()
|
or query_lower in value_field.lower()
|
||||||
or notes_match
|
or notes_match
|
||||||
or custom_match
|
or custom_match
|
||||||
|
or tags_match
|
||||||
):
|
):
|
||||||
results.append(
|
results.append(
|
||||||
(
|
(
|
||||||
@@ -942,7 +969,7 @@ class EntryManager:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if label_match or notes_match:
|
if label_match or notes_match or tags_match:
|
||||||
results.append(
|
results.append(
|
||||||
(
|
(
|
||||||
int(idx),
|
int(idx),
|
||||||
|
@@ -981,6 +981,12 @@ class PasswordManager:
|
|||||||
username = input("Enter the username (optional): ").strip()
|
username = input("Enter the username (optional): ").strip()
|
||||||
url = input("Enter the URL (optional): ").strip()
|
url = input("Enter the URL (optional): ").strip()
|
||||||
notes = input("Enter notes (optional): ").strip()
|
notes = input("Enter notes (optional): ").strip()
|
||||||
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
|
||||||
custom_fields: list[dict[str, object]] = []
|
custom_fields: list[dict[str, object]] = []
|
||||||
while True:
|
while True:
|
||||||
@@ -1021,6 +1027,7 @@ class PasswordManager:
|
|||||||
archived=False,
|
archived=False,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mark database as dirty for background sync
|
# Mark database as dirty for background sync
|
||||||
@@ -1084,6 +1091,14 @@ class PasswordManager:
|
|||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input(
|
||||||
|
"Enter tags (comma-separated, optional): "
|
||||||
|
).strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
totp_index = self.entry_manager.get_next_totp_index()
|
totp_index = self.entry_manager.get_next_totp_index()
|
||||||
entry_id = self.entry_manager.get_next_index()
|
entry_id = self.entry_manager.get_next_index()
|
||||||
uri = self.entry_manager.add_totp(
|
uri = self.entry_manager.add_totp(
|
||||||
@@ -1093,6 +1108,7 @@ class PasswordManager:
|
|||||||
period=int(period),
|
period=int(period),
|
||||||
digits=int(digits),
|
digits=int(digits),
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
secret = TotpManager.derive_secret(self.parent_seed, totp_index)
|
secret = TotpManager.derive_secret(self.parent_seed, totp_index)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
@@ -1128,6 +1144,14 @@ class PasswordManager:
|
|||||||
period = int(input("Period (default 30): ").strip() or 30)
|
period = int(input("Period (default 30): ").strip() or 30)
|
||||||
digits = int(input("Digits (default 6): ").strip() or 6)
|
digits = int(input("Digits (default 6): ").strip() or 6)
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input(
|
||||||
|
"Enter tags (comma-separated, optional): "
|
||||||
|
).strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
entry_id = self.entry_manager.get_next_index()
|
entry_id = self.entry_manager.get_next_index()
|
||||||
uri = self.entry_manager.add_totp(
|
uri = self.entry_manager.add_totp(
|
||||||
label,
|
label,
|
||||||
@@ -1136,6 +1160,7 @@ class PasswordManager:
|
|||||||
period=period,
|
period=period,
|
||||||
digits=digits,
|
digits=digits,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
self.last_update = time.time()
|
self.last_update = time.time()
|
||||||
@@ -1181,7 +1206,15 @@ class PasswordManager:
|
|||||||
print(colored("Error: Label cannot be empty.", "red"))
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
return
|
return
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
index = self.entry_manager.add_ssh_key(label, self.parent_seed, notes=notes)
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
index = self.entry_manager.add_ssh_key(
|
||||||
|
label, self.parent_seed, notes=notes, tags=tags
|
||||||
|
)
|
||||||
priv_pem, pub_pem = self.entry_manager.get_ssh_key_pair(
|
priv_pem, pub_pem = self.entry_manager.get_ssh_key_pair(
|
||||||
index, self.parent_seed
|
index, self.parent_seed
|
||||||
)
|
)
|
||||||
@@ -1230,12 +1263,18 @@ class PasswordManager:
|
|||||||
return
|
return
|
||||||
words_input = input("Word count (12 or 24, default 24): ").strip()
|
words_input = input("Word count (12 or 24, default 24): ").strip()
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
if words_input and words_input not in {"12", "24"}:
|
if words_input and words_input not in {"12", "24"}:
|
||||||
print(colored("Invalid word count. Choose 12 or 24.", "red"))
|
print(colored("Invalid word count. Choose 12 or 24.", "red"))
|
||||||
return
|
return
|
||||||
words = int(words_input) if words_input else 24
|
words = int(words_input) if words_input else 24
|
||||||
index = self.entry_manager.add_seed(
|
index = self.entry_manager.add_seed(
|
||||||
label, self.parent_seed, words_num=words, notes=notes
|
label, self.parent_seed, words_num=words, notes=notes, tags=tags
|
||||||
)
|
)
|
||||||
phrase = self.entry_manager.get_seed_phrase(index, self.parent_seed)
|
phrase = self.entry_manager.get_seed_phrase(index, self.parent_seed)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
@@ -1296,12 +1335,19 @@ class PasswordManager:
|
|||||||
)
|
)
|
||||||
user_id = input("User ID (optional): ").strip()
|
user_id = input("User ID (optional): ").strip()
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
index = self.entry_manager.add_pgp_key(
|
index = self.entry_manager.add_pgp_key(
|
||||||
label,
|
label,
|
||||||
self.parent_seed,
|
self.parent_seed,
|
||||||
key_type=key_type,
|
key_type=key_type,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
priv_key, fingerprint = self.entry_manager.get_pgp_key(
|
priv_key, fingerprint = self.entry_manager.get_pgp_key(
|
||||||
index, self.parent_seed
|
index, self.parent_seed
|
||||||
@@ -1350,7 +1396,13 @@ class PasswordManager:
|
|||||||
print(colored("Error: Label cannot be empty.", "red"))
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
return
|
return
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
index = self.entry_manager.add_nostr_key(label, notes=notes)
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
index = self.entry_manager.add_nostr_key(label, notes=notes, tags=tags)
|
||||||
npub, nsec = self.entry_manager.get_nostr_key_pair(index, self.parent_seed)
|
npub, nsec = self.entry_manager.get_nostr_key_pair(index, self.parent_seed)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
self.last_update = time.time()
|
self.last_update = time.time()
|
||||||
@@ -1401,6 +1453,12 @@ class PasswordManager:
|
|||||||
return
|
return
|
||||||
value = input("Value: ").strip()
|
value = input("Value: ").strip()
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
|
|
||||||
custom_fields: list[dict[str, object]] = []
|
custom_fields: list[dict[str, object]] = []
|
||||||
while True:
|
while True:
|
||||||
@@ -1419,7 +1477,11 @@ class PasswordManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
index = self.entry_manager.add_key_value(
|
index = self.entry_manager.add_key_value(
|
||||||
label, value, notes=notes, custom_fields=custom_fields
|
label,
|
||||||
|
value,
|
||||||
|
notes=notes,
|
||||||
|
custom_fields=custom_fields,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
self.last_update = time.time()
|
self.last_update = time.time()
|
||||||
@@ -1465,8 +1527,14 @@ class PasswordManager:
|
|||||||
print(colored("Error: Label cannot be empty.", "red"))
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
return
|
return
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
|
tags_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else []
|
||||||
|
)
|
||||||
index = self.entry_manager.add_managed_account(
|
index = self.entry_manager.add_managed_account(
|
||||||
label, self.parent_seed, notes=notes
|
label, self.parent_seed, notes=notes, tags=tags
|
||||||
)
|
)
|
||||||
seed = self.entry_manager.get_managed_account_seed(index, self.parent_seed)
|
seed = self.entry_manager.get_managed_account_seed(index, self.parent_seed)
|
||||||
self.is_dirty = True
|
self.is_dirty = True
|
||||||
@@ -2190,6 +2258,15 @@ class PasswordManager:
|
|||||||
{"label": label, "value": value, "is_hidden": hidden}
|
{"label": label, "value": value, "is_hidden": hidden}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tags_input = input(
|
||||||
|
"Enter tags (comma-separated, leave blank to keep current): "
|
||||||
|
).strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
self.entry_manager.modify_entry(
|
self.entry_manager.modify_entry(
|
||||||
index,
|
index,
|
||||||
archived=new_blacklisted,
|
archived=new_blacklisted,
|
||||||
@@ -2198,6 +2275,7 @@ class PasswordManager:
|
|||||||
period=new_period,
|
period=new_period,
|
||||||
digits=new_digits,
|
digits=new_digits,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
elif entry_type in (
|
elif entry_type in (
|
||||||
EntryType.KEY_VALUE.value,
|
EntryType.KEY_VALUE.value,
|
||||||
@@ -2273,6 +2351,15 @@ class PasswordManager:
|
|||||||
{"label": f_label, "value": f_value, "is_hidden": hidden}
|
{"label": f_label, "value": f_value, "is_hidden": hidden}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tags_input = input(
|
||||||
|
"Enter tags (comma-separated, leave blank to keep current): "
|
||||||
|
).strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
self.entry_manager.modify_entry(
|
self.entry_manager.modify_entry(
|
||||||
index,
|
index,
|
||||||
archived=new_blacklisted,
|
archived=new_blacklisted,
|
||||||
@@ -2280,6 +2367,7 @@ class PasswordManager:
|
|||||||
label=new_label,
|
label=new_label,
|
||||||
value=new_value,
|
value=new_value,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
website_name = entry.get("label", entry.get("website"))
|
website_name = entry.get("label", entry.get("website"))
|
||||||
@@ -2366,6 +2454,15 @@ class PasswordManager:
|
|||||||
{"label": label, "value": value, "is_hidden": hidden}
|
{"label": label, "value": value, "is_hidden": hidden}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tags_input = input(
|
||||||
|
"Enter tags (comma-separated, leave blank to keep current): "
|
||||||
|
).strip()
|
||||||
|
tags = (
|
||||||
|
[t.strip() for t in tags_input.split(",") if t.strip()]
|
||||||
|
if tags_input
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
self.entry_manager.modify_entry(
|
self.entry_manager.modify_entry(
|
||||||
index,
|
index,
|
||||||
new_username,
|
new_username,
|
||||||
@@ -2374,6 +2471,7 @@ class PasswordManager:
|
|||||||
notes=new_notes,
|
notes=new_notes,
|
||||||
label=new_label,
|
label=new_label,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
|
tags=tags,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mark database as dirty for background sync
|
# Mark database as dirty for background sync
|
||||||
|
@@ -39,6 +39,7 @@ def test_add_and_retrieve_entry():
|
|||||||
"kind": "password",
|
"kind": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"custom_fields": custom,
|
"custom_fields": custom,
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
data = enc_mgr.load_json_data(entry_mgr.index_file)
|
||||||
|
@@ -33,6 +33,7 @@ def test_add_and_modify_key_value():
|
|||||||
"notes": "token",
|
"notes": "token",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
"custom_fields": [],
|
"custom_fields": [],
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
em.modify_entry(idx, value="def456")
|
em.modify_entry(idx, value="def456")
|
||||||
|
@@ -48,6 +48,7 @@ def test_handle_add_totp(monkeypatch, capsys):
|
|||||||
"", # period
|
"", # period
|
||||||
"", # digits
|
"", # digits
|
||||||
"", # notes
|
"", # notes
|
||||||
|
"", # tags
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs))
|
monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs))
|
||||||
@@ -66,5 +67,6 @@ def test_handle_add_totp(monkeypatch, capsys):
|
|||||||
"digits": 6,
|
"digits": 6,
|
||||||
"archived": False,
|
"archived": False,
|
||||||
"notes": "",
|
"notes": "",
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
assert "ID 0" in out
|
assert "ID 0" in out
|
||||||
|
@@ -54,6 +54,7 @@ def test_manager_workflow(monkeypatch):
|
|||||||
"", # username
|
"", # username
|
||||||
"", # url
|
"", # url
|
||||||
"", # notes
|
"", # notes
|
||||||
|
"", # tags
|
||||||
"n", # add custom field
|
"n", # add custom field
|
||||||
"", # length (default)
|
"", # length (default)
|
||||||
"0", # retrieve index
|
"0", # retrieve index
|
||||||
@@ -65,6 +66,7 @@ def test_manager_workflow(monkeypatch):
|
|||||||
"", # archive status
|
"", # archive status
|
||||||
"", # new notes
|
"", # new notes
|
||||||
"n", # edit custom fields
|
"n", # edit custom fields
|
||||||
|
"", # tags keep
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs))
|
monkeypatch.setattr("builtins.input", lambda *args, **kwargs: next(inputs))
|
||||||
|
@@ -31,6 +31,7 @@ def test_nostr_key_determinism():
|
|||||||
"label": "main",
|
"label": "main",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
npub1, nsec1 = entry_mgr.get_nostr_key_pair(idx, TEST_SEED)
|
npub1, nsec1 = entry_mgr.get_nostr_key_pair(idx, TEST_SEED)
|
||||||
|
@@ -42,6 +42,7 @@ def test_seed_phrase_determinism():
|
|||||||
"word_count": 12,
|
"word_count": 12,
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
assert entry24 == {
|
assert entry24 == {
|
||||||
@@ -52,6 +53,7 @@ def test_seed_phrase_determinism():
|
|||||||
"word_count": 24,
|
"word_count": 24,
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
assert phrase12_a not in entry12.values()
|
assert phrase12_a not in entry12.values()
|
||||||
|
@@ -29,6 +29,7 @@ def test_add_and_retrieve_ssh_key_pair():
|
|||||||
"label": "ssh",
|
"label": "ssh",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
priv1, pub1 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
priv1, pub1 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
||||||
|
@@ -37,6 +37,7 @@ def test_add_totp_and_get_code():
|
|||||||
"digits": 6,
|
"digits": 6,
|
||||||
"archived": False,
|
"archived": False,
|
||||||
"notes": "",
|
"notes": "",
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
code = entry_mgr.get_totp_code(0, TEST_SEED, timestamp=0)
|
code = entry_mgr.get_totp_code(0, TEST_SEED, timestamp=0)
|
||||||
@@ -76,6 +77,7 @@ def test_add_totp_imported(tmp_path):
|
|||||||
"digits": 6,
|
"digits": 6,
|
||||||
"archived": False,
|
"archived": False,
|
||||||
"notes": "",
|
"notes": "",
|
||||||
|
"tags": [],
|
||||||
}
|
}
|
||||||
code = em.get_totp_code(0, timestamp=0)
|
code = em.get_totp_code(0, timestamp=0)
|
||||||
assert code == pyotp.TOTP(secret).at(0)
|
assert code == pyotp.TOTP(secret).at(0)
|
||||||
|
Reference in New Issue
Block a user