mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2025-09-08 07:18:47 +00:00
Merge pull request #683 from PR0M3TH3AN/codex/add-key-field-to-key/value-pair-entry
Add key field to key/value entries
This commit is contained in:
@@ -458,7 +458,7 @@ The table below summarizes the extra fields stored for each entry type. Every en
|
|||||||
| Seed Phrase | `index`, `word_count` *(mnemonic regenerated; never stored)*, `archived`, optional `notes`, optional `tags` |
|
| Seed Phrase | `index`, `word_count` *(mnemonic regenerated; never stored)*, `archived`, optional `notes`, optional `tags` |
|
||||||
| PGP Key | `index`, `key_type`, `archived`, optional `user_id`, optional `notes`, optional `tags` |
|
| PGP Key | `index`, `key_type`, `archived`, optional `user_id`, optional `notes`, optional `tags` |
|
||||||
| Nostr Key Pair | `index`, `archived`, optional `notes`, optional `tags` |
|
| Nostr Key Pair | `index`, `archived`, optional `notes`, optional `tags` |
|
||||||
| Key/Value | `value`, `archived`, optional `notes`, optional `custom_fields`, optional `tags` |
|
| Key/Value | `key`, `value`, `archived`, optional `notes`, optional `custom_fields`, optional `tags` |
|
||||||
| Managed Account | `index`, `word_count`, `fingerprint`, `archived`, optional `notes`, optional `tags` |
|
| Managed Account | `index`, `word_count`, `fingerprint`, `archived`, optional `notes`, optional `tags` |
|
||||||
|
|
||||||
### Managing Multiple Seeds
|
### Managing Multiple Seeds
|
||||||
|
@@ -55,7 +55,7 @@ Manage individual entries within a vault.
|
|||||||
| Add a PGP key entry | `entry add-pgp` | `seedpass entry add-pgp Personal --user-id me@example.com` |
|
| Add a PGP key entry | `entry add-pgp` | `seedpass entry add-pgp Personal --user-id me@example.com` |
|
||||||
| Add a Nostr key entry | `entry add-nostr` | `seedpass entry add-nostr Chat` |
|
| Add a Nostr key entry | `entry add-nostr` | `seedpass entry add-nostr Chat` |
|
||||||
| Add a seed phrase entry | `entry add-seed` | `seedpass entry add-seed Backup --words 24` |
|
| Add a seed phrase entry | `entry add-seed` | `seedpass entry add-seed Backup --words 24` |
|
||||||
| Add a key/value entry | `entry add-key-value` | `seedpass entry add-key-value "API Token" --value abc123` |
|
| Add a key/value entry | `entry add-key-value` | `seedpass entry add-key-value "API Token" --key api --value abc123` |
|
||||||
| Add a managed account entry | `entry add-managed-account` | `seedpass entry add-managed-account Trading` |
|
| Add a managed account entry | `entry add-managed-account` | `seedpass entry add-managed-account Trading` |
|
||||||
| Modify an entry | `entry modify` | `seedpass entry modify 1 --username alice` |
|
| Modify an entry | `entry modify` | `seedpass entry modify 1 --username alice` |
|
||||||
| Archive an entry | `entry archive` | `seedpass entry archive 1` |
|
| Archive an entry | `entry archive` | `seedpass entry archive 1` |
|
||||||
@@ -144,7 +144,7 @@ Run or stop the local HTTP API.
|
|||||||
- **`seedpass entry add-pgp <label>`** – Create a PGP key entry. Provide `--user-id` and `--key-type` as needed.
|
- **`seedpass entry add-pgp <label>`** – Create a PGP key entry. Provide `--user-id` and `--key-type` as needed.
|
||||||
- **`seedpass entry add-nostr <label>`** – Create a Nostr key entry for decentralised chat.
|
- **`seedpass entry add-nostr <label>`** – Create a Nostr key entry for decentralised chat.
|
||||||
- **`seedpass entry add-seed <label>`** – Store a derived seed phrase. Use `--words` to set the word count.
|
- **`seedpass entry add-seed <label>`** – Store a derived seed phrase. Use `--words` to set the word count.
|
||||||
- **`seedpass entry add-key-value <label>`** – Store arbitrary data with `--value`.
|
- **`seedpass entry add-key-value <label>`** – Store arbitrary data with `--key` and `--value`.
|
||||||
- **`seedpass entry add-managed-account <label>`** – Store a BIP‑85 derived account seed.
|
- **`seedpass entry add-managed-account <label>`** – Store a BIP‑85 derived account seed.
|
||||||
- **`seedpass entry modify <id>`** – Update an entry's label, username, URL or notes.
|
- **`seedpass entry modify <id>`** – Update an entry's label, username, URL or notes.
|
||||||
- **`seedpass entry archive <id>`** – Mark an entry as archived so it is hidden from normal lists.
|
- **`seedpass entry archive <id>`** – Mark an entry as archived so it is hidden from normal lists.
|
||||||
|
@@ -95,6 +95,7 @@ Each entry is stored within `seedpass_entries_db.json.enc` under the `entries` d
|
|||||||
- **custom_fields** (`array`, optional): Additional user-defined fields.
|
- **custom_fields** (`array`, optional): Additional user-defined fields.
|
||||||
- **origin** (`string`, optional): Source identifier for imported data.
|
- **origin** (`string`, optional): Source identifier for imported data.
|
||||||
- **value** (`string`, optional): For `key_value` entries, stores the secret value.
|
- **value** (`string`, optional): For `key_value` entries, stores the secret value.
|
||||||
|
- **key** (`string`, optional): Name of the key for `key_value` entries.
|
||||||
- **index** (`integer`, optional): BIP-85 derivation index for entries that derive material from a seed.
|
- **index** (`integer`, optional): BIP-85 derivation index for entries that derive material from a seed.
|
||||||
- **word_count** (`integer`, managed_account only): Number of words in the child seed. Managed accounts always use `12`.
|
- **word_count** (`integer`, managed_account only): Number of words in the child seed. Managed accounts always use `12`.
|
||||||
- **fingerprint** (`string`, managed_account only): Identifier of the child profile, used for its directory name.
|
- **fingerprint** (`string`, managed_account only): Identifier of the child profile, used for its directory name.
|
||||||
|
@@ -363,7 +363,7 @@ entry includes a `label`, while only password entries track a `url`.
|
|||||||
| Seed Phrase | `index`, `word_count` *(mnemonic regenerated; never stored)*, `archived`, optional `notes`, optional `tags` |
|
| Seed Phrase | `index`, `word_count` *(mnemonic regenerated; never stored)*, `archived`, optional `notes`, optional `tags` |
|
||||||
| PGP Key | `index`, `key_type`, `archived`, optional `user_id`, optional `notes`, optional `tags` |
|
| PGP Key | `index`, `key_type`, `archived`, optional `user_id`, optional `notes`, optional `tags` |
|
||||||
| Nostr Key Pair| `index`, `archived`, optional `notes`, optional `tags` |
|
| Nostr Key Pair| `index`, `archived`, optional `notes`, optional `tags` |
|
||||||
| Key/Value | `value`, `archived`, optional `notes`, optional `custom_fields`, optional `tags` |
|
| Key/Value | `key`, `value`, `archived`, optional `notes`, optional `custom_fields`, optional `tags` |
|
||||||
| Managed Account | `index`, `word_count`, `fingerprint`, `archived`, optional `notes`, optional `tags` |
|
| Managed Account | `index`, `word_count`, `fingerprint`, `archived`, optional `notes`, optional `tags` |
|
||||||
|
|
||||||
|
|
||||||
|
@@ -173,6 +173,7 @@ def create_entry(
|
|||||||
if etype == "key_value":
|
if etype == "key_value":
|
||||||
index = _pm.entry_manager.add_key_value(
|
index = _pm.entry_manager.add_key_value(
|
||||||
entry.get("label"),
|
entry.get("label"),
|
||||||
|
entry.get("key"),
|
||||||
entry.get("value"),
|
entry.get("value"),
|
||||||
notes=entry.get("notes", ""),
|
notes=entry.get("notes", ""),
|
||||||
)
|
)
|
||||||
|
@@ -315,12 +315,13 @@ def entry_add_seed(
|
|||||||
def entry_add_key_value(
|
def entry_add_key_value(
|
||||||
ctx: typer.Context,
|
ctx: typer.Context,
|
||||||
label: str,
|
label: str,
|
||||||
|
key: str = typer.Option(..., "--key", help="Key name"),
|
||||||
value: str = typer.Option(..., "--value", help="Stored value"),
|
value: str = typer.Option(..., "--value", help="Stored value"),
|
||||||
notes: str = typer.Option("", "--notes", help="Entry notes"),
|
notes: str = typer.Option("", "--notes", help="Entry notes"),
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Add a key/value entry and output its index."""
|
"""Add a key/value entry and output its index."""
|
||||||
service = _get_entry_service(ctx)
|
service = _get_entry_service(ctx)
|
||||||
idx = service.add_key_value(label, value, notes=notes)
|
idx = service.add_key_value(label, key, value, notes=notes)
|
||||||
typer.echo(str(idx))
|
typer.echo(str(idx))
|
||||||
|
|
||||||
|
|
||||||
|
@@ -379,9 +379,13 @@ class EntryService:
|
|||||||
self._manager.start_background_vault_sync()
|
self._manager.start_background_vault_sync()
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
def add_key_value(self, label: str, value: str, *, notes: str = "") -> int:
|
def add_key_value(
|
||||||
|
self, label: str, key: str, value: str, *, notes: str = ""
|
||||||
|
) -> int:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
idx = self._manager.entry_manager.add_key_value(label, value, notes=notes)
|
idx = self._manager.entry_manager.add_key_value(
|
||||||
|
label, key, value, notes=notes
|
||||||
|
)
|
||||||
self._manager.start_background_vault_sync()
|
self._manager.start_background_vault_sync()
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
@@ -412,6 +412,7 @@ class EntryManager:
|
|||||||
def add_key_value(
|
def add_key_value(
|
||||||
self,
|
self,
|
||||||
label: str,
|
label: str,
|
||||||
|
key: str,
|
||||||
value: str,
|
value: str,
|
||||||
*,
|
*,
|
||||||
notes: str = "",
|
notes: str = "",
|
||||||
@@ -429,6 +430,7 @@ class EntryManager:
|
|||||||
"type": EntryType.KEY_VALUE.value,
|
"type": EntryType.KEY_VALUE.value,
|
||||||
"kind": EntryType.KEY_VALUE.value,
|
"kind": EntryType.KEY_VALUE.value,
|
||||||
"label": label,
|
"label": label,
|
||||||
|
"key": key,
|
||||||
"modified_ts": int(time.time()),
|
"modified_ts": int(time.time()),
|
||||||
"value": value,
|
"value": value,
|
||||||
"notes": notes,
|
"notes": notes,
|
||||||
@@ -720,6 +722,7 @@ class EntryManager:
|
|||||||
label: Optional[str] = None,
|
label: Optional[str] = None,
|
||||||
period: Optional[int] = None,
|
period: Optional[int] = None,
|
||||||
digits: Optional[int] = None,
|
digits: Optional[int] = None,
|
||||||
|
key: Optional[str] = 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,
|
tags: list[str] | None = None,
|
||||||
@@ -736,6 +739,7 @@ class EntryManager:
|
|||||||
:param label: (Optional) The new label for the entry.
|
:param label: (Optional) The new label for the entry.
|
||||||
:param period: (Optional) The new TOTP period in seconds.
|
:param period: (Optional) The new TOTP period in seconds.
|
||||||
:param digits: (Optional) The new number of digits for TOTP codes.
|
:param digits: (Optional) The new number of digits for TOTP codes.
|
||||||
|
:param key: (Optional) New key for key/value entries.
|
||||||
:param value: (Optional) New value for key/value entries.
|
:param value: (Optional) New value for key/value entries.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
@@ -764,6 +768,7 @@ class EntryManager:
|
|||||||
"label": label,
|
"label": label,
|
||||||
"period": period,
|
"period": period,
|
||||||
"digits": digits,
|
"digits": digits,
|
||||||
|
"key": key,
|
||||||
"value": value,
|
"value": value,
|
||||||
"custom_fields": custom_fields,
|
"custom_fields": custom_fields,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
@@ -790,6 +795,7 @@ class EntryManager:
|
|||||||
},
|
},
|
||||||
EntryType.KEY_VALUE.value: {
|
EntryType.KEY_VALUE.value: {
|
||||||
"label",
|
"label",
|
||||||
|
"key",
|
||||||
"value",
|
"value",
|
||||||
"archived",
|
"archived",
|
||||||
"notes",
|
"notes",
|
||||||
@@ -870,6 +876,9 @@ class EntryManager:
|
|||||||
EntryType.KEY_VALUE.value,
|
EntryType.KEY_VALUE.value,
|
||||||
EntryType.MANAGED_ACCOUNT.value,
|
EntryType.MANAGED_ACCOUNT.value,
|
||||||
):
|
):
|
||||||
|
if key is not None and entry_type == EntryType.KEY_VALUE.value:
|
||||||
|
entry["key"] = key
|
||||||
|
logger.debug(f"Updated key for index {index}.")
|
||||||
if value is not None:
|
if value is not None:
|
||||||
entry["value"] = value
|
entry["value"] = value
|
||||||
logger.debug(f"Updated value for index {index}.")
|
logger.debug(f"Updated value for index {index}.")
|
||||||
|
@@ -1888,6 +1888,10 @@ class PasswordManager:
|
|||||||
if not label:
|
if not label:
|
||||||
print(colored("Error: Label cannot be empty.", "red"))
|
print(colored("Error: Label cannot be empty.", "red"))
|
||||||
return
|
return
|
||||||
|
key_field = input("Key: ").strip()
|
||||||
|
if not key_field:
|
||||||
|
print(colored("Error: Key cannot be empty.", "red"))
|
||||||
|
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_input = input("Enter tags (comma-separated, optional): ").strip()
|
||||||
@@ -1915,6 +1919,7 @@ class PasswordManager:
|
|||||||
|
|
||||||
index = self.entry_manager.add_key_value(
|
index = self.entry_manager.add_key_value(
|
||||||
label,
|
label,
|
||||||
|
key_field,
|
||||||
value,
|
value,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
@@ -2886,6 +2891,9 @@ class PasswordManager:
|
|||||||
input(f'Enter new label (leave blank to keep "{label}"): ').strip()
|
input(f'Enter new label (leave blank to keep "{label}"): ').strip()
|
||||||
or label
|
or label
|
||||||
)
|
)
|
||||||
|
new_key = input(
|
||||||
|
f'Enter new key (leave blank to keep "{entry.get("key", "")}"): '
|
||||||
|
).strip() or entry.get("key", "")
|
||||||
new_value = (
|
new_value = (
|
||||||
input("Enter new value (leave blank to keep current): ").strip()
|
input("Enter new value (leave blank to keep current): ").strip()
|
||||||
or value
|
or value
|
||||||
@@ -2947,6 +2955,7 @@ class PasswordManager:
|
|||||||
archived=new_blacklisted,
|
archived=new_blacklisted,
|
||||||
notes=new_notes,
|
notes=new_notes,
|
||||||
label=new_label,
|
label=new_label,
|
||||||
|
key=new_key,
|
||||||
value=new_value,
|
value=new_value,
|
||||||
custom_fields=custom_fields,
|
custom_fields=custom_fields,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
@@ -3237,7 +3246,8 @@ class PasswordManager:
|
|||||||
print(color_text(f" Tags: {', '.join(tags)}", "index"))
|
print(color_text(f" Tags: {', '.join(tags)}", "index"))
|
||||||
elif etype == EntryType.KEY_VALUE.value:
|
elif etype == EntryType.KEY_VALUE.value:
|
||||||
print(color_text(" Type: Key/Value", "index"))
|
print(color_text(" Type: Key/Value", "index"))
|
||||||
print(color_text(f" Label (key): {entry.get('label', '')}", "index"))
|
print(color_text(f" Label: {entry.get('label', '')}", "index"))
|
||||||
|
print(color_text(f" Key: {entry.get('key', '')}", "index"))
|
||||||
print(color_text(f" Value: {entry.get('value', '')}", "index"))
|
print(color_text(f" Value: {entry.get('value', '')}", "index"))
|
||||||
notes = entry.get("notes", "")
|
notes = entry.get("notes", "")
|
||||||
if notes:
|
if notes:
|
||||||
|
@@ -217,6 +217,7 @@ class EntryDialog(toga.Window):
|
|||||||
self.length_input = toga.NumberInput(
|
self.length_input = toga.NumberInput(
|
||||||
min=8, max=128, style=Pack(width=80), value=16
|
min=8, max=128, style=Pack(width=80), value=16
|
||||||
)
|
)
|
||||||
|
self.key_input = toga.TextInput(style=Pack(flex=1))
|
||||||
self.value_input = toga.TextInput(style=Pack(flex=1))
|
self.value_input = toga.TextInput(style=Pack(flex=1))
|
||||||
|
|
||||||
save_button = toga.Button(
|
save_button = toga.Button(
|
||||||
@@ -234,6 +235,8 @@ class EntryDialog(toga.Window):
|
|||||||
box.add(self.url_input)
|
box.add(self.url_input)
|
||||||
box.add(toga.Label("Length"))
|
box.add(toga.Label("Length"))
|
||||||
box.add(self.length_input)
|
box.add(self.length_input)
|
||||||
|
box.add(toga.Label("Key"))
|
||||||
|
box.add(self.key_input)
|
||||||
box.add(toga.Label("Value"))
|
box.add(toga.Label("Value"))
|
||||||
box.add(self.value_input)
|
box.add(self.value_input)
|
||||||
box.add(save_button)
|
box.add(save_button)
|
||||||
@@ -249,6 +252,7 @@ class EntryDialog(toga.Window):
|
|||||||
self.username_input.value = entry.get("username", "") or ""
|
self.username_input.value = entry.get("username", "") or ""
|
||||||
self.url_input.value = entry.get("url", "") or ""
|
self.url_input.value = entry.get("url", "") or ""
|
||||||
self.length_input.value = entry.get("length", 16)
|
self.length_input.value = entry.get("length", 16)
|
||||||
|
self.key_input.value = entry.get("key", "")
|
||||||
self.value_input.value = entry.get("value", "")
|
self.value_input.value = entry.get("value", "")
|
||||||
|
|
||||||
def save(self, widget: toga.Widget) -> None:
|
def save(self, widget: toga.Widget) -> None:
|
||||||
@@ -257,6 +261,7 @@ class EntryDialog(toga.Window):
|
|||||||
url = self.url_input.value or None
|
url = self.url_input.value or None
|
||||||
length = int(self.length_input.value or 16)
|
length = int(self.length_input.value or 16)
|
||||||
kind = self.kind_input.value
|
kind = self.kind_input.value
|
||||||
|
key = self.key_input.value or None
|
||||||
value = self.value_input.value or None
|
value = self.value_input.value or None
|
||||||
|
|
||||||
if self.entry_id is None:
|
if self.entry_id is None:
|
||||||
@@ -275,7 +280,9 @@ class EntryDialog(toga.Window):
|
|||||||
elif kind == EntryType.NOSTR.value:
|
elif kind == EntryType.NOSTR.value:
|
||||||
entry_id = self.main.entries.add_nostr_key(label)
|
entry_id = self.main.entries.add_nostr_key(label)
|
||||||
elif kind == EntryType.KEY_VALUE.value:
|
elif kind == EntryType.KEY_VALUE.value:
|
||||||
entry_id = self.main.entries.add_key_value(label, value or "")
|
entry_id = self.main.entries.add_key_value(
|
||||||
|
label, key or "", value or ""
|
||||||
|
)
|
||||||
elif kind == EntryType.MANAGED_ACCOUNT.value:
|
elif kind == EntryType.MANAGED_ACCOUNT.value:
|
||||||
entry_id = self.main.entries.add_managed_account(label)
|
entry_id = self.main.entries.add_managed_account(label)
|
||||||
else:
|
else:
|
||||||
@@ -284,7 +291,7 @@ class EntryDialog(toga.Window):
|
|||||||
if kind == EntryType.PASSWORD.value:
|
if kind == EntryType.PASSWORD.value:
|
||||||
kwargs.update({"username": username, "url": url})
|
kwargs.update({"username": username, "url": url})
|
||||||
elif kind == EntryType.KEY_VALUE.value:
|
elif kind == EntryType.KEY_VALUE.value:
|
||||||
kwargs.update({"value": value})
|
kwargs.update({"key": key, "value": value})
|
||||||
self.main.entries.modify_entry(entry_id, **kwargs)
|
self.main.entries.modify_entry(entry_id, **kwargs)
|
||||||
|
|
||||||
entry = self.main.entries.retrieve_entry(entry_id) or {}
|
entry = self.main.entries.retrieve_entry(entry_id) or {}
|
||||||
|
@@ -26,7 +26,7 @@ class DummyPM:
|
|||||||
add_pgp_key=lambda label, seed, index=None, key_type="ed25519", user_id="", notes="": 3,
|
add_pgp_key=lambda label, seed, index=None, key_type="ed25519", user_id="", notes="": 3,
|
||||||
add_nostr_key=lambda label, index=None, notes="": 4,
|
add_nostr_key=lambda label, index=None, notes="": 4,
|
||||||
add_seed=lambda label, seed, index=None, words_num=24, notes="": 5,
|
add_seed=lambda label, seed, index=None, words_num=24, notes="": 5,
|
||||||
add_key_value=lambda label, value, notes="": 6,
|
add_key_value=lambda label, key, value, notes="": 6,
|
||||||
add_managed_account=lambda label, seed, index=None, notes="": 7,
|
add_managed_account=lambda label, seed, index=None, notes="": 7,
|
||||||
modify_entry=lambda *a, **kw: None,
|
modify_entry=lambda *a, **kw: None,
|
||||||
archive_entry=lambda i: None,
|
archive_entry=lambda i: None,
|
||||||
|
@@ -90,8 +90,8 @@ runner = CliRunner()
|
|||||||
(
|
(
|
||||||
"add-key-value",
|
"add-key-value",
|
||||||
"add_key_value",
|
"add_key_value",
|
||||||
["Label", "--value", "val", "--notes", "note"],
|
["Label", "--key", "k1", "--value", "val", "--notes", "note"],
|
||||||
("Label", "val"),
|
("Label", "k1", "val"),
|
||||||
{"notes": "note"},
|
{"notes": "note"},
|
||||||
"7",
|
"7",
|
||||||
),
|
),
|
||||||
|
@@ -73,7 +73,7 @@ def test_round_trip_entry_types(method, expected_type):
|
|||||||
entry_mgr.add_totp("example", TEST_SEED)
|
entry_mgr.add_totp("example", TEST_SEED)
|
||||||
index = 0
|
index = 0
|
||||||
elif method == "add_key_value":
|
elif method == "add_key_value":
|
||||||
index = entry_mgr.add_key_value("label", "val")
|
index = entry_mgr.add_key_value("label", "k1", "val")
|
||||||
else:
|
else:
|
||||||
if method == "add_ssh_key":
|
if method == "add_ssh_key":
|
||||||
index = entry_mgr.add_ssh_key("ssh", TEST_SEED)
|
index = entry_mgr.add_ssh_key("ssh", TEST_SEED)
|
||||||
@@ -118,7 +118,7 @@ def test_legacy_entry_defaults_to_password():
|
|||||||
("add_pgp_key", ("pgp", TEST_SEED)),
|
("add_pgp_key", ("pgp", TEST_SEED)),
|
||||||
("add_nostr_key", ("nostr",)),
|
("add_nostr_key", ("nostr",)),
|
||||||
("add_seed", ("seed", TEST_SEED)),
|
("add_seed", ("seed", TEST_SEED)),
|
||||||
("add_key_value", ("label", "val")),
|
("add_key_value", ("label", "k1", "val")),
|
||||||
("add_managed_account", ("acct", TEST_SEED)),
|
("add_managed_account", ("acct", TEST_SEED)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@@ -53,16 +53,18 @@ class FakeEntries:
|
|||||||
self.added.append(("nostr", label))
|
self.added.append(("nostr", label))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def add_key_value(self, label, value):
|
def add_key_value(self, label, key, value):
|
||||||
self.added.append(("key_value", label, value))
|
self.added.append(("key_value", label, key, value))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def add_managed_account(self, label):
|
def add_managed_account(self, label):
|
||||||
self.added.append(("managed_account", label))
|
self.added.append(("managed_account", label))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def modify_entry(self, entry_id, username=None, url=None, label=None, value=None):
|
def modify_entry(
|
||||||
self.modified.append((entry_id, username, url, label, value))
|
self, entry_id, username=None, url=None, label=None, key=None, value=None
|
||||||
|
):
|
||||||
|
self.modified.append((entry_id, username, url, label, key, value))
|
||||||
|
|
||||||
|
|
||||||
def setup_module(module):
|
def setup_module(module):
|
||||||
@@ -106,7 +108,7 @@ def test_unlock_creates_main_window():
|
|||||||
(EntryType.SEED.value, ("seed", "L")),
|
(EntryType.SEED.value, ("seed", "L")),
|
||||||
(EntryType.PGP.value, ("pgp", "L")),
|
(EntryType.PGP.value, ("pgp", "L")),
|
||||||
(EntryType.NOSTR.value, ("nostr", "L")),
|
(EntryType.NOSTR.value, ("nostr", "L")),
|
||||||
(EntryType.KEY_VALUE.value, ("key_value", "L", "val")),
|
(EntryType.KEY_VALUE.value, ("key_value", "L", "k1", "val")),
|
||||||
(EntryType.MANAGED_ACCOUNT.value, ("managed_account", "L")),
|
(EntryType.MANAGED_ACCOUNT.value, ("managed_account", "L")),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@@ -123,6 +125,7 @@ def test_entrydialog_add_calls_service(kind, expect):
|
|||||||
dlg.username_input.value = "u"
|
dlg.username_input.value = "u"
|
||||||
dlg.url_input.value = "x"
|
dlg.url_input.value = "x"
|
||||||
dlg.length_input.value = 12
|
dlg.length_input.value = 12
|
||||||
|
dlg.key_input.value = "k1"
|
||||||
dlg.value_input.value = "val"
|
dlg.value_input.value = "val"
|
||||||
dlg.save(None)
|
dlg.save(None)
|
||||||
|
|
||||||
@@ -136,9 +139,9 @@ def test_entrydialog_add_calls_service(kind, expect):
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"kind,expected",
|
"kind,expected",
|
||||||
[
|
[
|
||||||
(EntryType.PASSWORD.value, (1, "newu", "newx", "New", None)),
|
(EntryType.PASSWORD.value, (1, "newu", "newx", "New", None, None)),
|
||||||
(EntryType.KEY_VALUE.value, (1, None, None, "New", "val2")),
|
(EntryType.KEY_VALUE.value, (1, None, None, "New", "k2", "val2")),
|
||||||
(EntryType.TOTP.value, (1, None, None, "New", None)),
|
(EntryType.TOTP.value, (1, None, None, "New", None, None)),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_entrydialog_edit_calls_service(kind, expected):
|
def test_entrydialog_edit_calls_service(kind, expected):
|
||||||
@@ -157,6 +160,7 @@ def test_entrydialog_edit_calls_service(kind, expected):
|
|||||||
dlg.kind_input.value = kind
|
dlg.kind_input.value = kind
|
||||||
dlg.username_input.value = "newu"
|
dlg.username_input.value = "newu"
|
||||||
dlg.url_input.value = "newx"
|
dlg.url_input.value = "newx"
|
||||||
|
dlg.key_input.value = "k2"
|
||||||
dlg.value_input.value = "val2"
|
dlg.value_input.value = "val2"
|
||||||
dlg.save(None)
|
dlg.save(None)
|
||||||
|
|
||||||
|
@@ -23,12 +23,13 @@ def test_add_and_modify_key_value():
|
|||||||
tmp_path = Path(tmpdir)
|
tmp_path = Path(tmpdir)
|
||||||
em = setup_entry_mgr(tmp_path)
|
em = setup_entry_mgr(tmp_path)
|
||||||
|
|
||||||
idx = em.add_key_value("API", "abc123", notes="token")
|
idx = em.add_key_value("API entry", "api_key", "abc123", notes="token")
|
||||||
entry = em.retrieve_entry(idx)
|
entry = em.retrieve_entry(idx)
|
||||||
assert entry == {
|
assert entry == {
|
||||||
"type": "key_value",
|
"type": "key_value",
|
||||||
"kind": "key_value",
|
"kind": "key_value",
|
||||||
"label": "API",
|
"label": "API entry",
|
||||||
|
"key": "api_key",
|
||||||
"value": "abc123",
|
"value": "abc123",
|
||||||
"notes": "token",
|
"notes": "token",
|
||||||
"archived": False,
|
"archived": False,
|
||||||
@@ -36,8 +37,9 @@ def test_add_and_modify_key_value():
|
|||||||
"tags": [],
|
"tags": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
em.modify_entry(idx, value="def456")
|
em.modify_entry(idx, key="api_key2", value="def456")
|
||||||
updated = em.retrieve_entry(idx)
|
updated = em.retrieve_entry(idx)
|
||||||
|
assert updated["key"] == "api_key2"
|
||||||
assert updated["value"] == "def456"
|
assert updated["value"] == "def456"
|
||||||
|
|
||||||
results = em.search_entries("def456")
|
results = em.search_entries("def456")
|
||||||
|
@@ -38,7 +38,7 @@ def test_handle_list_entries(monkeypatch, capsys):
|
|||||||
|
|
||||||
entry_mgr.add_totp("Example", TEST_SEED)
|
entry_mgr.add_totp("Example", TEST_SEED)
|
||||||
entry_mgr.add_entry("example.com", 12)
|
entry_mgr.add_entry("example.com", 12)
|
||||||
entry_mgr.add_key_value("API", "abc123")
|
entry_mgr.add_key_value("API entry", "api", "abc123")
|
||||||
entry_mgr.add_managed_account("acct", TEST_SEED)
|
entry_mgr.add_managed_account("acct", TEST_SEED)
|
||||||
|
|
||||||
inputs = iter(["1", ""]) # list all, then exit
|
inputs = iter(["1", ""]) # list all, then exit
|
||||||
@@ -72,7 +72,7 @@ def test_list_entries_show_details(monkeypatch, capsys):
|
|||||||
pm.secret_mode_enabled = False
|
pm.secret_mode_enabled = False
|
||||||
|
|
||||||
entry_mgr.add_totp("Example", TEST_SEED)
|
entry_mgr.add_totp("Example", TEST_SEED)
|
||||||
entry_mgr.add_key_value("API", "val")
|
entry_mgr.add_key_value("API entry", "api", "val")
|
||||||
entry_mgr.add_managed_account("acct", TEST_SEED)
|
entry_mgr.add_managed_account("acct", TEST_SEED)
|
||||||
|
|
||||||
monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456")
|
monkeypatch.setattr(pm.entry_manager, "get_totp_code", lambda *a, **k: "123456")
|
||||||
@@ -353,7 +353,7 @@ def test_show_entry_details_sensitive(monkeypatch, capsys, entry_type):
|
|||||||
)
|
)
|
||||||
expected = "123456"
|
expected = "123456"
|
||||||
elif entry_type == "key_value":
|
elif entry_type == "key_value":
|
||||||
idx = entry_mgr.add_key_value("API", "abc")
|
idx = entry_mgr.add_key_value("API entry", "api", "abc")
|
||||||
expected = "abc"
|
expected = "abc"
|
||||||
else: # managed_account
|
else: # managed_account
|
||||||
idx = entry_mgr.add_managed_account("acct", TEST_SEED)
|
idx = entry_mgr.add_managed_account("acct", TEST_SEED)
|
||||||
@@ -390,8 +390,8 @@ def test_show_entry_details_with_enum_type(monkeypatch, capsys, entry_type):
|
|||||||
)
|
)
|
||||||
expect = "Label: Example"
|
expect = "Label: Example"
|
||||||
else: # KEY_VALUE
|
else: # KEY_VALUE
|
||||||
idx = entry_mgr.add_key_value("API", "abc")
|
idx = entry_mgr.add_key_value("API entry", "api", "abc")
|
||||||
expect = "API"
|
expect = "API entry"
|
||||||
|
|
||||||
data = entry_mgr._load_index(force_reload=True)
|
data = entry_mgr._load_index(force_reload=True)
|
||||||
data["entries"][str(idx)]["type"] = entry_type
|
data["entries"][str(idx)]["type"] = entry_type
|
||||||
|
@@ -93,7 +93,7 @@ def test_search_key_value_value():
|
|||||||
tmp_path = Path(tmpdir)
|
tmp_path = Path(tmpdir)
|
||||||
entry_mgr = setup_entry_manager(tmp_path)
|
entry_mgr = setup_entry_manager(tmp_path)
|
||||||
|
|
||||||
idx = entry_mgr.add_key_value("API", "token123")
|
idx = entry_mgr.add_key_value("API entry", "api", "token123")
|
||||||
|
|
||||||
result = entry_mgr.search_entries("token123")
|
result = entry_mgr.search_entries("token123")
|
||||||
assert result == []
|
assert result == []
|
||||||
|
Reference in New Issue
Block a user