mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-09 15:58:48 +00:00
Remove deprecated website field
This commit is contained in:
@@ -169,7 +169,7 @@ seedpass totp "email"
|
|||||||
# The code is printed and copied to your clipboard
|
# The code is printed and copied to your clipboard
|
||||||
|
|
||||||
# Sort or filter the list view
|
# Sort or filter the list view
|
||||||
seedpass list --sort website
|
seedpass list --sort label
|
||||||
seedpass list --filter totp
|
seedpass list --filter totp
|
||||||
|
|
||||||
# Use the **Settings** menu to configure an extra backup directory
|
# Use the **Settings** menu to configure an extra backup directory
|
||||||
@@ -185,7 +185,7 @@ The encrypted index file `seedpass_entries_db.json.enc` begins with `schema_vers
|
|||||||
"schema_version": 2,
|
"schema_version": 2,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "example.com",
|
"label": "example.com",
|
||||||
"length": 8,
|
"length": 8,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
@@ -53,7 +53,7 @@ The following table provides a quick reference to all available advanced CLI com
|
|||||||
| Retrieve a password entry | `retrieve` | `-R` | `--retrieve` | `seedpass retrieve --index 3` or `seedpass retrieve --title "GitHub"` |
|
| Retrieve a password entry | `retrieve` | `-R` | `--retrieve` | `seedpass retrieve --index 3` or `seedpass retrieve --title "GitHub"` |
|
||||||
| Modify an existing entry | `modify` | `-M` | `--modify` | `seedpass modify --index 3 --title "GitHub Pro" --notes "Updated to pro account" --tags "work,development,pro" --length 22` |
|
| Modify an existing entry | `modify` | `-M` | `--modify` | `seedpass modify --index 3 --title "GitHub Pro" --notes "Updated to pro account" --tags "work,development,pro" --length 22` |
|
||||||
| Delete an entry | `delete` | `-D` | `--delete` | `seedpass delete --index 3` |
|
| Delete an entry | `delete` | `-D` | `--delete` | `seedpass delete --index 3` |
|
||||||
| List all entries | `list` | `-L` | `--list` | `seedpass list --sort website` |
|
| List all entries | `list` | `-L` | `--list` | `seedpass list --sort label` |
|
||||||
| Search for a password entry | `search` | `-S` | `--search` | `seedpass search "GitHub"` |
|
| Search for a password entry | `search` | `-S` | `--search` | `seedpass search "GitHub"` |
|
||||||
| Get password from query | `get` | | | `seedpass get "GitHub"`
|
| Get password from query | `get` | | | `seedpass get "GitHub"`
|
||||||
| Display a TOTP code | `totp` | | | `seedpass totp "email"`
|
| Display a TOTP code | `totp` | | | `seedpass totp "email"`
|
||||||
@@ -179,11 +179,11 @@ seedpass delete --index 3
|
|||||||
**Long Flag:** `--list`
|
**Long Flag:** `--list`
|
||||||
|
|
||||||
**Description:**
|
**Description:**
|
||||||
Lists all password entries stored in the password manager. You can sort the output by index, website, or username and filter by entry type.
|
Lists all password entries stored in the password manager. You can sort the output by index, label, or username and filter by entry type.
|
||||||
|
|
||||||
**Usage Example:**
|
**Usage Example:**
|
||||||
```bash
|
```bash
|
||||||
seedpass list --sort website
|
seedpass list --sort label
|
||||||
seedpass list --filter totp
|
seedpass list --filter totp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -42,7 +42,7 @@ All entries belonging to a seed profile are summarized in an encrypted file name
|
|||||||
"schema_version": 2,
|
"schema_version": 2,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "example.com",
|
"label": "example.com",
|
||||||
"length": 8,
|
"length": 8,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
|
@@ -262,7 +262,7 @@ def print_matches(
|
|||||||
print(colored(" Type: Nostr Key", "cyan"))
|
print(colored(" Type: Nostr Key", "cyan"))
|
||||||
else:
|
else:
|
||||||
if website:
|
if website:
|
||||||
print(colored(f" Website: {website}", "cyan"))
|
print(colored(f" Label: {website}", "cyan"))
|
||||||
if username:
|
if username:
|
||||||
print(colored(f" Username: {username}", "cyan"))
|
print(colored(f" Username: {username}", "cyan"))
|
||||||
if url:
|
if url:
|
||||||
|
@@ -65,6 +65,13 @@ class EntryManager:
|
|||||||
if "kind" not in entry:
|
if "kind" not in entry:
|
||||||
entry["kind"] = entry.get("type", EntryType.PASSWORD.value)
|
entry["kind"] = entry.get("type", EntryType.PASSWORD.value)
|
||||||
entry.setdefault("type", entry["kind"])
|
entry.setdefault("type", entry["kind"])
|
||||||
|
if "label" not in entry and "website" in entry:
|
||||||
|
entry["label"] = entry["website"]
|
||||||
|
if (
|
||||||
|
"website" in entry
|
||||||
|
and entry.get("type") == EntryType.PASSWORD.value
|
||||||
|
):
|
||||||
|
entry.pop("website", None)
|
||||||
logger.debug("Index loaded successfully.")
|
logger.debug("Index loaded successfully.")
|
||||||
return data
|
return data
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -106,7 +113,7 @@ class EntryManager:
|
|||||||
|
|
||||||
def add_entry(
|
def add_entry(
|
||||||
self,
|
self,
|
||||||
website_name: str,
|
label: str,
|
||||||
length: int,
|
length: int,
|
||||||
username: Optional[str] = None,
|
username: Optional[str] = None,
|
||||||
url: Optional[str] = None,
|
url: Optional[str] = None,
|
||||||
@@ -117,7 +124,7 @@ class EntryManager:
|
|||||||
"""
|
"""
|
||||||
Adds a new entry to the encrypted JSON index file.
|
Adds a new entry to the encrypted JSON index file.
|
||||||
|
|
||||||
:param website_name: The name of the website.
|
:param label: A label describing the entry (e.g. website name).
|
||||||
:param length: The desired length of the password.
|
:param length: The desired length of the password.
|
||||||
:param username: (Optional) The username associated with the website.
|
:param username: (Optional) The username associated with the website.
|
||||||
:param url: (Optional) The URL of the website.
|
:param url: (Optional) The URL of the website.
|
||||||
@@ -131,7 +138,7 @@ class EntryManager:
|
|||||||
|
|
||||||
data.setdefault("entries", {})
|
data.setdefault("entries", {})
|
||||||
data["entries"][str(index)] = {
|
data["entries"][str(index)] = {
|
||||||
"website": website_name,
|
"label": label,
|
||||||
"length": length,
|
"length": length,
|
||||||
"username": username if username else "",
|
"username": username if username else "",
|
||||||
"url": url if url else "",
|
"url": url if url else "",
|
||||||
@@ -222,7 +229,11 @@ class EntryManager:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
def add_ssh_key(
|
def add_ssh_key(
|
||||||
self, parent_seed: str, index: int | None = None, notes: str = ""
|
self,
|
||||||
|
label: str,
|
||||||
|
parent_seed: str,
|
||||||
|
index: int | None = None,
|
||||||
|
notes: str = "",
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Add a new SSH key pair entry.
|
"""Add a new SSH key pair entry.
|
||||||
|
|
||||||
@@ -240,6 +251,7 @@ class EntryManager:
|
|||||||
"type": EntryType.SSH.value,
|
"type": EntryType.SSH.value,
|
||||||
"kind": EntryType.SSH.value,
|
"kind": EntryType.SSH.value,
|
||||||
"index": index,
|
"index": index,
|
||||||
|
"label": label,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
}
|
}
|
||||||
self._save_index(data)
|
self._save_index(data)
|
||||||
@@ -263,6 +275,7 @@ class EntryManager:
|
|||||||
|
|
||||||
def add_pgp_key(
|
def add_pgp_key(
|
||||||
self,
|
self,
|
||||||
|
label: str,
|
||||||
parent_seed: str,
|
parent_seed: str,
|
||||||
index: int | None = None,
|
index: int | None = None,
|
||||||
key_type: str = "ed25519",
|
key_type: str = "ed25519",
|
||||||
@@ -280,6 +293,7 @@ class EntryManager:
|
|||||||
"type": EntryType.PGP.value,
|
"type": EntryType.PGP.value,
|
||||||
"kind": EntryType.PGP.value,
|
"kind": EntryType.PGP.value,
|
||||||
"index": index,
|
"index": index,
|
||||||
|
"label": label,
|
||||||
"key_type": key_type,
|
"key_type": key_type,
|
||||||
"user_id": user_id,
|
"user_id": user_id,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
@@ -362,6 +376,7 @@ class EntryManager:
|
|||||||
|
|
||||||
def add_seed(
|
def add_seed(
|
||||||
self,
|
self,
|
||||||
|
label: str,
|
||||||
parent_seed: str,
|
parent_seed: str,
|
||||||
index: int | None = None,
|
index: int | None = None,
|
||||||
words_num: int = 24,
|
words_num: int = 24,
|
||||||
@@ -378,6 +393,7 @@ class EntryManager:
|
|||||||
"type": EntryType.SEED.value,
|
"type": EntryType.SEED.value,
|
||||||
"kind": EntryType.SEED.value,
|
"kind": EntryType.SEED.value,
|
||||||
"index": index,
|
"index": index,
|
||||||
|
"label": label,
|
||||||
"words": words_num,
|
"words": words_num,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
}
|
}
|
||||||
@@ -596,11 +612,11 @@ class EntryManager:
|
|||||||
idx_str, entry = item
|
idx_str, entry = item
|
||||||
if sort_by == "index":
|
if sort_by == "index":
|
||||||
return int(idx_str)
|
return int(idx_str)
|
||||||
if sort_by == "website":
|
if sort_by in {"website", "label"}:
|
||||||
return entry.get("website", "").lower()
|
return entry.get("label", entry.get("website", "")).lower()
|
||||||
if sort_by == "username":
|
if sort_by == "username":
|
||||||
return entry.get("username", "").lower()
|
return entry.get("username", "").lower()
|
||||||
raise ValueError("sort_by must be 'index', 'website', or 'username'")
|
raise ValueError("sort_by must be 'index', 'label', or 'username'")
|
||||||
|
|
||||||
sorted_items = sorted(entries_data.items(), key=sort_key)
|
sorted_items = sorted(entries_data.items(), key=sort_key)
|
||||||
|
|
||||||
@@ -616,19 +632,20 @@ class EntryManager:
|
|||||||
|
|
||||||
entries: List[Tuple[int, str, Optional[str], Optional[str], bool]] = []
|
entries: List[Tuple[int, str, Optional[str], Optional[str], bool]] = []
|
||||||
for idx, entry in filtered_items:
|
for idx, entry in filtered_items:
|
||||||
|
label = entry.get("label", entry.get("website", ""))
|
||||||
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
||||||
if etype == EntryType.TOTP.value:
|
if etype == EntryType.PASSWORD.value:
|
||||||
entries.append((idx, entry.get("label", ""), None, None, False))
|
|
||||||
else:
|
|
||||||
entries.append(
|
entries.append(
|
||||||
(
|
(
|
||||||
idx,
|
idx,
|
||||||
entry.get("website", ""),
|
label,
|
||||||
entry.get("username", ""),
|
entry.get("username", ""),
|
||||||
entry.get("url", ""),
|
entry.get("url", ""),
|
||||||
entry.get("blacklisted", False),
|
entry.get("blacklisted", False),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
entries.append((idx, label, None, None, False))
|
||||||
|
|
||||||
logger.debug(f"Total entries found: {len(entries)}")
|
logger.debug(f"Total entries found: {len(entries)}")
|
||||||
for idx, entry in filtered_items:
|
for idx, entry in filtered_items:
|
||||||
@@ -644,8 +661,13 @@ class EntryManager:
|
|||||||
"cyan",
|
"cyan",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
elif etype == EntryType.PASSWORD.value:
|
||||||
print(colored(f" Website: {entry.get('website', '')}", "cyan"))
|
print(
|
||||||
|
colored(
|
||||||
|
f" Label: {entry.get('label', entry.get('website', ''))}",
|
||||||
|
"cyan",
|
||||||
|
)
|
||||||
|
)
|
||||||
print(
|
print(
|
||||||
colored(f" Username: {entry.get('username') or 'N/A'}", "cyan")
|
colored(f" Username: {entry.get('username') or 'N/A'}", "cyan")
|
||||||
)
|
)
|
||||||
@@ -656,6 +678,13 @@ class EntryManager:
|
|||||||
"cyan",
|
"cyan",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
|
||||||
|
print(
|
||||||
|
colored(
|
||||||
|
f" Derivation Index: {entry.get('index', index)}", "cyan"
|
||||||
|
)
|
||||||
|
)
|
||||||
print("-" * 40)
|
print("-" * 40)
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
@@ -680,16 +709,14 @@ class EntryManager:
|
|||||||
|
|
||||||
for idx, entry in sorted(entries_data.items(), key=lambda x: int(x[0])):
|
for idx, entry in sorted(entries_data.items(), key=lambda x: int(x[0])):
|
||||||
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
etype = entry.get("type", entry.get("kind", EntryType.PASSWORD.value))
|
||||||
if etype == EntryType.TOTP.value:
|
label = entry.get("label", entry.get("website", ""))
|
||||||
label = entry.get("label", "")
|
|
||||||
notes = entry.get("notes", "")
|
notes = entry.get("notes", "")
|
||||||
if query_lower in label.lower() or query_lower in notes.lower():
|
label_match = query_lower in label.lower()
|
||||||
results.append((int(idx), label, None, None, False))
|
notes_match = query_lower in notes.lower()
|
||||||
else:
|
|
||||||
website = entry.get("website", "")
|
if etype == EntryType.PASSWORD.value:
|
||||||
username = entry.get("username", "")
|
username = entry.get("username", "")
|
||||||
url = entry.get("url", "")
|
url = entry.get("url", "")
|
||||||
notes = entry.get("notes", "")
|
|
||||||
custom_fields = entry.get("custom_fields", [])
|
custom_fields = entry.get("custom_fields", [])
|
||||||
custom_match = any(
|
custom_match = any(
|
||||||
query_lower in str(cf.get("label", "")).lower()
|
query_lower in str(cf.get("label", "")).lower()
|
||||||
@@ -697,21 +724,24 @@ class EntryManager:
|
|||||||
for cf in custom_fields
|
for cf in custom_fields
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
query_lower in website.lower()
|
label_match
|
||||||
or query_lower in username.lower()
|
or query_lower in username.lower()
|
||||||
or query_lower in url.lower()
|
or query_lower in url.lower()
|
||||||
or query_lower in notes.lower()
|
or notes_match
|
||||||
or custom_match
|
or custom_match
|
||||||
):
|
):
|
||||||
results.append(
|
results.append(
|
||||||
(
|
(
|
||||||
int(idx),
|
int(idx),
|
||||||
website,
|
label,
|
||||||
username,
|
username,
|
||||||
url,
|
url,
|
||||||
entry.get("blacklisted", False),
|
entry.get("blacklisted", False),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
if label_match or notes_match:
|
||||||
|
results.append((int(idx), label, None, None, False))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@@ -829,7 +859,7 @@ class EntryManager:
|
|||||||
for entry in entries:
|
for entry in entries:
|
||||||
index, website, username, url, blacklisted = entry
|
index, website, username, url, blacklisted = entry
|
||||||
print(colored(f"Index: {index}", "cyan"))
|
print(colored(f"Index: {index}", "cyan"))
|
||||||
print(colored(f" Website: {website}", "cyan"))
|
print(colored(f" Label: {website}", "cyan"))
|
||||||
print(colored(f" Username: {username or 'N/A'}", "cyan"))
|
print(colored(f" Username: {username or 'N/A'}", "cyan"))
|
||||||
print(colored(f" URL: {url or 'N/A'}", "cyan"))
|
print(colored(f" URL: {url or 'N/A'}", "cyan"))
|
||||||
print(
|
print(
|
||||||
@@ -856,19 +886,9 @@ class EntryManager:
|
|||||||
if filter_kind and etype != filter_kind:
|
if filter_kind and etype != filter_kind:
|
||||||
continue
|
continue
|
||||||
if etype == EntryType.PASSWORD.value:
|
if etype == EntryType.PASSWORD.value:
|
||||||
label = entry.get("website", "")
|
label = entry.get("label", entry.get("website", ""))
|
||||||
elif etype == EntryType.TOTP.value:
|
|
||||||
label = entry.get("label", "")
|
|
||||||
elif etype == EntryType.SSH.value:
|
|
||||||
label = "SSH Key"
|
|
||||||
elif etype == EntryType.SEED.value:
|
|
||||||
label = "Seed Phrase"
|
|
||||||
elif etype == EntryType.NOSTR.value:
|
|
||||||
label = entry.get("label", "Nostr Key")
|
|
||||||
elif etype == EntryType.PGP.value:
|
|
||||||
label = "PGP Key"
|
|
||||||
else:
|
else:
|
||||||
label = etype
|
label = entry.get("label", etype)
|
||||||
summaries.append((int(idx_str), label))
|
summaries.append((int(idx_str), label))
|
||||||
|
|
||||||
summaries.sort(key=lambda x: x[0])
|
summaries.sort(key=lambda x: x[0])
|
||||||
|
@@ -859,9 +859,9 @@ class PasswordManager:
|
|||||||
|
|
||||||
def handle_add_password(self) -> None:
|
def handle_add_password(self) -> None:
|
||||||
try:
|
try:
|
||||||
website_name = input("Enter the website name: ").strip()
|
website_name = input("Enter the label or website name: ").strip()
|
||||||
if not website_name:
|
if not website_name:
|
||||||
print(colored("Error: Website name cannot be empty.", "red"))
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
return
|
return
|
||||||
|
|
||||||
username = input("Enter the username (optional): ").strip()
|
username = input("Enter the username (optional): ").strip()
|
||||||
@@ -1040,8 +1040,12 @@ class PasswordManager:
|
|||||||
def handle_add_ssh_key(self) -> None:
|
def handle_add_ssh_key(self) -> None:
|
||||||
"""Add an SSH key pair entry and display the derived keys."""
|
"""Add an SSH key pair entry and display the derived keys."""
|
||||||
try:
|
try:
|
||||||
|
label = input("Label: ").strip()
|
||||||
|
if not label:
|
||||||
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
|
return
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
index = self.entry_manager.add_ssh_key(self.parent_seed, notes=notes)
|
index = self.entry_manager.add_ssh_key(label, self.parent_seed, notes=notes)
|
||||||
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
|
||||||
)
|
)
|
||||||
@@ -1075,6 +1079,10 @@ class PasswordManager:
|
|||||||
def handle_add_seed(self) -> None:
|
def handle_add_seed(self) -> None:
|
||||||
"""Add a derived BIP-39 seed phrase entry."""
|
"""Add a derived BIP-39 seed phrase entry."""
|
||||||
try:
|
try:
|
||||||
|
label = input("Label: ").strip()
|
||||||
|
if not label:
|
||||||
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
|
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()
|
||||||
if words_input and words_input not in {"12", "24"}:
|
if words_input and words_input not in {"12", "24"}:
|
||||||
@@ -1082,7 +1090,7 @@ class PasswordManager:
|
|||||||
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(
|
||||||
self.parent_seed, words_num=words, notes=notes
|
label, self.parent_seed, words_num=words, notes=notes
|
||||||
)
|
)
|
||||||
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
|
||||||
@@ -1117,6 +1125,10 @@ class PasswordManager:
|
|||||||
def handle_add_pgp(self) -> None:
|
def handle_add_pgp(self) -> None:
|
||||||
"""Add a PGP key entry and display the generated key."""
|
"""Add a PGP key entry and display the generated key."""
|
||||||
try:
|
try:
|
||||||
|
label = input("Label: ").strip()
|
||||||
|
if not label:
|
||||||
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
|
return
|
||||||
key_type = (
|
key_type = (
|
||||||
input("Key type (ed25519 or rsa, default ed25519): ").strip().lower()
|
input("Key type (ed25519 or rsa, default ed25519): ").strip().lower()
|
||||||
or "ed25519"
|
or "ed25519"
|
||||||
@@ -1124,6 +1136,7 @@ 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()
|
||||||
index = self.entry_manager.add_pgp_key(
|
index = self.entry_manager.add_pgp_key(
|
||||||
|
label,
|
||||||
self.parent_seed,
|
self.parent_seed,
|
||||||
key_type=key_type,
|
key_type=key_type,
|
||||||
user_id=user_id,
|
user_id=user_id,
|
||||||
@@ -1162,7 +1175,10 @@ class PasswordManager:
|
|||||||
def handle_add_nostr_key(self) -> None:
|
def handle_add_nostr_key(self) -> None:
|
||||||
"""Add a Nostr key entry and display the derived keys."""
|
"""Add a Nostr key entry and display the derived keys."""
|
||||||
try:
|
try:
|
||||||
label = input("Label (optional): ").strip()
|
label = input("Label: ").strip()
|
||||||
|
if not label:
|
||||||
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
|
return
|
||||||
notes = input("Notes (optional): ").strip()
|
notes = input("Notes (optional): ").strip()
|
||||||
index = self.entry_manager.add_nostr_key(label, notes=notes)
|
index = self.entry_manager.add_nostr_key(label, notes=notes)
|
||||||
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)
|
||||||
@@ -1779,6 +1795,7 @@ class PasswordManager:
|
|||||||
print(colored(f" Notes: {notes}", "cyan"))
|
print(colored(f" Notes: {notes}", "cyan"))
|
||||||
elif etype == EntryType.SEED.value:
|
elif etype == EntryType.SEED.value:
|
||||||
print(colored(" Type: Seed Phrase", "cyan"))
|
print(colored(" Type: Seed Phrase", "cyan"))
|
||||||
|
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
|
||||||
print(colored(f" Words: {entry.get('words', 24)}", "cyan"))
|
print(colored(f" Words: {entry.get('words', 24)}", "cyan"))
|
||||||
print(colored(f" Derivation Index: {entry.get('index', index)}", "cyan"))
|
print(colored(f" Derivation Index: {entry.get('index', index)}", "cyan"))
|
||||||
notes = entry.get("notes", "")
|
notes = entry.get("notes", "")
|
||||||
@@ -1786,12 +1803,14 @@ class PasswordManager:
|
|||||||
print(colored(f" Notes: {notes}", "cyan"))
|
print(colored(f" Notes: {notes}", "cyan"))
|
||||||
elif etype == EntryType.SSH.value:
|
elif etype == EntryType.SSH.value:
|
||||||
print(colored(" Type: SSH Key", "cyan"))
|
print(colored(" Type: SSH Key", "cyan"))
|
||||||
|
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
|
||||||
print(colored(f" Derivation Index: {entry.get('index', index)}", "cyan"))
|
print(colored(f" Derivation Index: {entry.get('index', index)}", "cyan"))
|
||||||
notes = entry.get("notes", "")
|
notes = entry.get("notes", "")
|
||||||
if notes:
|
if notes:
|
||||||
print(colored(f" Notes: {notes}", "cyan"))
|
print(colored(f" Notes: {notes}", "cyan"))
|
||||||
elif etype == EntryType.PGP.value:
|
elif etype == EntryType.PGP.value:
|
||||||
print(colored(" Type: PGP Key", "cyan"))
|
print(colored(" Type: PGP Key", "cyan"))
|
||||||
|
print(colored(f" Label: {entry.get('label', '')}", "cyan"))
|
||||||
print(colored(f" Key Type: {entry.get('key_type', 'ed25519')}", "cyan"))
|
print(colored(f" Key Type: {entry.get('key_type', 'ed25519')}", "cyan"))
|
||||||
uid = entry.get("user_id", "")
|
uid = entry.get("user_id", "")
|
||||||
if uid:
|
if uid:
|
||||||
@@ -1808,11 +1827,11 @@ class PasswordManager:
|
|||||||
if notes:
|
if notes:
|
||||||
print(colored(f" Notes: {notes}", "cyan"))
|
print(colored(f" Notes: {notes}", "cyan"))
|
||||||
else:
|
else:
|
||||||
website = entry.get("website", "")
|
website = entry.get("label", entry.get("website", ""))
|
||||||
username = entry.get("username", "")
|
username = entry.get("username", "")
|
||||||
url = entry.get("url", "")
|
url = entry.get("url", "")
|
||||||
blacklisted = entry.get("blacklisted", False)
|
blacklisted = entry.get("blacklisted", False)
|
||||||
print(colored(f" Website: {website}", "cyan"))
|
print(colored(f" Label: {website}", "cyan"))
|
||||||
print(colored(f" Username: {username or 'N/A'}", "cyan"))
|
print(colored(f" Username: {username or 'N/A'}", "cyan"))
|
||||||
print(colored(f" URL: {url or 'N/A'}", "cyan"))
|
print(colored(f" URL: {url or 'N/A'}", "cyan"))
|
||||||
print(colored(f" Blacklisted: {'Yes' if blacklisted else 'No'}", "cyan"))
|
print(colored(f" Blacklisted: {'Yes' if blacklisted else 'No'}", "cyan"))
|
||||||
|
@@ -33,6 +33,10 @@ def _v1_to_v2(data: dict) -> dict:
|
|||||||
for k, v in passwords.items():
|
for k, v in passwords.items():
|
||||||
v.setdefault("type", "password")
|
v.setdefault("type", "password")
|
||||||
v.setdefault("notes", "")
|
v.setdefault("notes", "")
|
||||||
|
if "label" not in v and "website" in v:
|
||||||
|
v["label"] = v["website"]
|
||||||
|
if v.get("type") == "password" and "website" in v:
|
||||||
|
v.pop("website", None)
|
||||||
entries[k] = v
|
entries[k] = v
|
||||||
data["entries"] = entries
|
data["entries"] = entries
|
||||||
data["schema_version"] = 2
|
data["schema_version"] = 2
|
||||||
@@ -46,6 +50,10 @@ def _v2_to_v3(data: dict) -> dict:
|
|||||||
for entry in entries.values():
|
for entry in entries.values():
|
||||||
entry.setdefault("custom_fields", [])
|
entry.setdefault("custom_fields", [])
|
||||||
entry.setdefault("origin", "")
|
entry.setdefault("origin", "")
|
||||||
|
if entry.get("type", "password") == "password":
|
||||||
|
if "label" not in entry and "website" in entry:
|
||||||
|
entry["label"] = entry["website"]
|
||||||
|
entry.pop("website", None)
|
||||||
data["schema_version"] = 3
|
data["schema_version"] = 3
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ def test_backup_restore_workflow(monkeypatch):
|
|||||||
"schema_version": 3,
|
"schema_version": 3,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "a",
|
"label": "a",
|
||||||
"length": 10,
|
"length": 10,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"kind": "password",
|
"kind": "password",
|
||||||
@@ -48,7 +48,7 @@ def test_backup_restore_workflow(monkeypatch):
|
|||||||
"schema_version": 3,
|
"schema_version": 3,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "b",
|
"label": "b",
|
||||||
"length": 12,
|
"length": 12,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"kind": "password",
|
"kind": "password",
|
||||||
|
@@ -30,7 +30,7 @@ def test_add_and_retrieve_entry():
|
|||||||
entry = entry_mgr.retrieve_entry(index)
|
entry = entry_mgr.retrieve_entry(index)
|
||||||
|
|
||||||
assert entry == {
|
assert entry == {
|
||||||
"website": "example.com",
|
"label": "example.com",
|
||||||
"length": 12,
|
"length": 12,
|
||||||
"username": "user",
|
"username": "user",
|
||||||
"url": "",
|
"url": "",
|
||||||
@@ -69,9 +69,9 @@ def test_round_trip_entry_types(method, expected_type):
|
|||||||
index = 0
|
index = 0
|
||||||
else:
|
else:
|
||||||
if method == "add_ssh_key":
|
if method == "add_ssh_key":
|
||||||
index = entry_mgr.add_ssh_key(TEST_SEED)
|
index = entry_mgr.add_ssh_key("ssh", TEST_SEED)
|
||||||
elif method == "add_seed":
|
elif method == "add_seed":
|
||||||
index = entry_mgr.add_seed(TEST_SEED)
|
index = entry_mgr.add_seed("seed", TEST_SEED)
|
||||||
else:
|
else:
|
||||||
index = getattr(entry_mgr, method)()
|
index = getattr(entry_mgr, method)()
|
||||||
|
|
||||||
|
@@ -34,7 +34,7 @@ def test_index_export_import_round_trip():
|
|||||||
"schema_version": 3,
|
"schema_version": 3,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "example",
|
"label": "example",
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"custom_fields": [],
|
"custom_fields": [],
|
||||||
@@ -52,7 +52,7 @@ def test_index_export_import_round_trip():
|
|||||||
"schema_version": 3,
|
"schema_version": 3,
|
||||||
"entries": {
|
"entries": {
|
||||||
"0": {
|
"0": {
|
||||||
"website": "changed",
|
"label": "changed",
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"custom_fields": [],
|
"custom_fields": [],
|
||||||
|
@@ -20,7 +20,7 @@ def test_migrate_v0_to_v3(tmp_path: Path):
|
|||||||
data = vault.load_index()
|
data = vault.load_index()
|
||||||
assert data["schema_version"] == LATEST_VERSION
|
assert data["schema_version"] == LATEST_VERSION
|
||||||
expected_entry = {
|
expected_entry = {
|
||||||
"website": "a",
|
"label": "a",
|
||||||
"length": 8,
|
"length": 8,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
@@ -37,7 +37,7 @@ def test_migrate_v1_to_v3(tmp_path: Path):
|
|||||||
data = vault.load_index()
|
data = vault.load_index()
|
||||||
assert data["schema_version"] == LATEST_VERSION
|
assert data["schema_version"] == LATEST_VERSION
|
||||||
expected_entry = {
|
expected_entry = {
|
||||||
"website": "b",
|
"label": "b",
|
||||||
"length": 10,
|
"length": 10,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
@@ -59,7 +59,7 @@ def test_migrate_v2_to_v3(tmp_path: Path):
|
|||||||
data = vault.load_index()
|
data = vault.load_index()
|
||||||
assert data["schema_version"] == LATEST_VERSION
|
assert data["schema_version"] == LATEST_VERSION
|
||||||
expected_entry = {
|
expected_entry = {
|
||||||
"website": "c",
|
"label": "c",
|
||||||
"length": 5,
|
"length": 5,
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
|
@@ -58,7 +58,7 @@ def test_nostr_index_size_limits(pytestconfig: pytest.Config):
|
|||||||
if max_entries is not None and entry_count >= max_entries:
|
if max_entries is not None and entry_count >= max_entries:
|
||||||
break
|
break
|
||||||
entry_mgr.add_entry(
|
entry_mgr.add_entry(
|
||||||
website_name=f"site-{entry_count + 1}",
|
label=f"site-{entry_count + 1}",
|
||||||
length=12,
|
length=12,
|
||||||
username="u" * size,
|
username="u" * size,
|
||||||
url="https://example.com/" + "a" * size,
|
url="https://example.com/" + "a" * size,
|
||||||
|
@@ -19,7 +19,9 @@ def test_pgp_key_determinism():
|
|||||||
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
||||||
entry_mgr = EntryManager(vault, backup_mgr)
|
entry_mgr = EntryManager(vault, backup_mgr)
|
||||||
|
|
||||||
idx = entry_mgr.add_pgp_key(TEST_SEED, key_type="ed25519", user_id="Test")
|
idx = entry_mgr.add_pgp_key(
|
||||||
|
"pgp", TEST_SEED, key_type="ed25519", user_id="Test"
|
||||||
|
)
|
||||||
key1, fp1 = entry_mgr.get_pgp_key(idx, TEST_SEED)
|
key1, fp1 = entry_mgr.get_pgp_key(idx, TEST_SEED)
|
||||||
key2, fp2 = entry_mgr.get_pgp_key(idx, TEST_SEED)
|
key2, fp2 = entry_mgr.get_pgp_key(idx, TEST_SEED)
|
||||||
|
|
||||||
|
@@ -23,8 +23,8 @@ def test_seed_phrase_determinism():
|
|||||||
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
||||||
entry_mgr = EntryManager(vault, backup_mgr)
|
entry_mgr = EntryManager(vault, backup_mgr)
|
||||||
|
|
||||||
idx_12 = entry_mgr.add_seed(TEST_SEED, words_num=12)
|
idx_12 = entry_mgr.add_seed("seed12", TEST_SEED, words_num=12)
|
||||||
idx_24 = entry_mgr.add_seed(TEST_SEED, words_num=24)
|
idx_24 = entry_mgr.add_seed("seed24", TEST_SEED, words_num=24)
|
||||||
|
|
||||||
phrase12_a = entry_mgr.get_seed_phrase(idx_12, TEST_SEED)
|
phrase12_a = entry_mgr.get_seed_phrase(idx_12, TEST_SEED)
|
||||||
phrase12_b = entry_mgr.get_seed_phrase(idx_12, TEST_SEED)
|
phrase12_b = entry_mgr.get_seed_phrase(idx_12, TEST_SEED)
|
||||||
|
@@ -20,9 +20,15 @@ def test_add_and_retrieve_ssh_key_pair():
|
|||||||
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
||||||
entry_mgr = EntryManager(vault, backup_mgr)
|
entry_mgr = EntryManager(vault, backup_mgr)
|
||||||
|
|
||||||
index = entry_mgr.add_ssh_key(TEST_SEED)
|
index = entry_mgr.add_ssh_key("ssh", TEST_SEED)
|
||||||
entry = entry_mgr.retrieve_entry(index)
|
entry = entry_mgr.retrieve_entry(index)
|
||||||
assert entry == {"type": "ssh", "kind": "ssh", "index": index, "notes": ""}
|
assert entry == {
|
||||||
|
"type": "ssh",
|
||||||
|
"kind": "ssh",
|
||||||
|
"index": index,
|
||||||
|
"label": "ssh",
|
||||||
|
"notes": "",
|
||||||
|
}
|
||||||
|
|
||||||
priv1, pub1 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
priv1, pub1 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
||||||
priv2, pub2 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
priv2, pub2 = entry_mgr.get_ssh_key_pair(index, TEST_SEED)
|
||||||
|
@@ -21,7 +21,7 @@ def test_ssh_private_key_corresponds_to_public():
|
|||||||
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
backup_mgr = BackupManager(tmp_path, cfg_mgr)
|
||||||
entry_mgr = EntryManager(vault, backup_mgr)
|
entry_mgr = EntryManager(vault, backup_mgr)
|
||||||
|
|
||||||
idx = entry_mgr.add_ssh_key(TEST_SEED)
|
idx = entry_mgr.add_ssh_key("ssh", TEST_SEED)
|
||||||
priv_pem, pub_pem = entry_mgr.get_ssh_key_pair(idx, TEST_SEED)
|
priv_pem, pub_pem = entry_mgr.get_ssh_key_pair(idx, TEST_SEED)
|
||||||
|
|
||||||
priv_key = serialization.load_pem_private_key(
|
priv_key = serialization.load_pem_private_key(
|
||||||
|
Reference in New Issue
Block a user