keepassxc-cli 0.3.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of keepassxc-cli might be problematic. Click here for more details.

Files changed (36) hide show
  1. {keepassxc_cli-0.3.0/keepassxc_cli.egg-info → keepassxc_cli-1.1.0}/PKG-INFO +2 -2
  2. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/show.py +2 -1
  3. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/output.py +20 -3
  4. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0/keepassxc_cli.egg-info}/PKG-INFO +2 -2
  5. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/requires.txt +1 -1
  6. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/pyproject.toml +1 -1
  7. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/conftest.py +0 -3
  8. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/test_commands.py +13 -2
  9. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/test_output.py +15 -0
  10. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/auto-merge-dependabot.yml +0 -0
  11. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/auto-release.yml +0 -0
  12. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/lint_and_test.yml +0 -0
  13. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/pypi.yml +0 -0
  14. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.gitignore +0 -0
  15. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/CLAUDE.md +0 -0
  16. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/LICENSE +0 -0
  17. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/README.md +0 -0
  18. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/__init__.py +0 -0
  19. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/__main__.py +0 -0
  20. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/__init__.py +0 -0
  21. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/add.py +0 -0
  22. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/clip.py +0 -0
  23. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/edit.py +0 -0
  24. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/lock.py +0 -0
  25. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/mkdir.py +0 -0
  26. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/rm.py +0 -0
  27. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/setup.py +0 -0
  28. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/status.py +0 -0
  29. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/totp.py +0 -0
  30. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/config.py +0 -0
  31. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/SOURCES.txt +0 -0
  32. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/dependency_links.txt +0 -0
  33. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/entry_points.txt +0 -0
  34. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/top_level.txt +0 -0
  35. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/setup.cfg +0 -0
  36. {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/test_config.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keepassxc-cli
3
- Version: 0.3.0
3
+ Version: 1.1.0
4
4
  Summary: CLI for KeePassXC using the browser extension protocol with biometric unlock
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: keepassxc-browser-api==0.1.3
9
+ Requires-Dist: keepassxc-browser-api==1.0.0
10
10
  Requires-Dist: pyperclip==1.8.0
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: pytest>=7.0; extra == "dev"
@@ -15,6 +15,7 @@ def add_parser(subparsers: argparse._SubParsersAction, fmt_parent: argparse.Argu
15
15
  p = subparsers.add_parser("show", parents=parents, help="Show entries matching a URL")
16
16
  p.add_argument("url", help="URL or search string")
17
17
  p.add_argument("-p", "--show-password", action="store_true", help="Reveal password and TOTP")
18
+ p.add_argument("--show-kph-prefix", action="store_true", help="Keep 'KPH: ' prefix on custom string field names")
18
19
  p.set_defaults(func=run)
19
20
 
20
21
 
@@ -32,7 +33,7 @@ def run(
32
33
  print(f"No entries found for: {args.url}", file=sys.stderr)
33
34
  return 1
34
35
  for entry in entries:
35
- print_entry_detail(entry, fmt, show_password=args.show_password)
36
+ print_entry_detail(entry, fmt, show_password=args.show_password, show_kph_prefix=getattr(args, "show_kph_prefix", False))
36
37
  if fmt == "table" and len(entries) > 1:
37
38
  print()
38
39
  return 0
@@ -4,9 +4,26 @@ import json
4
4
 
5
5
  from keepassxc_browser_api import Entry
6
6
 
7
+ _KPH_PREFIX = "KPH: "
7
8
 
8
- def print_entry_detail(entry: Entry, fmt: str = "table", show_password: bool = False) -> None:
9
+
10
+ def _strip_kph(key: str) -> str:
11
+ return key[len(_KPH_PREFIX):] if key.startswith(_KPH_PREFIX) else key
12
+
13
+
14
+ def print_entry_detail(
15
+ entry: Entry,
16
+ fmt: str = "table",
17
+ show_password: bool = False,
18
+ show_kph_prefix: bool = False,
19
+ ) -> None:
9
20
  totp = entry.totp if show_password else None
21
+
22
+ def _fields() -> list[dict[str, str]]:
23
+ if show_kph_prefix:
24
+ return entry.string_fields
25
+ return [{_strip_kph(k): v for k, v in sf.items()} for sf in entry.string_fields]
26
+
10
27
  if fmt == "json":
11
28
  data = {
12
29
  "uuid": entry.uuid,
@@ -14,7 +31,7 @@ def print_entry_detail(entry: Entry, fmt: str = "table", show_password: bool = F
14
31
  "login": entry.login,
15
32
  "group": entry.group,
16
33
  "group_uuid": entry.group_uuid,
17
- "string_fields": entry.string_fields,
34
+ "string_fields": _fields(),
18
35
  }
19
36
  if show_password:
20
37
  data["password"] = entry.password
@@ -35,7 +52,7 @@ def print_entry_detail(entry: Entry, fmt: str = "table", show_password: bool = F
35
52
  if entry.group_uuid:
36
53
  print(f"Group UUID: {entry.group_uuid}")
37
54
  if entry.string_fields:
38
- for sf in entry.string_fields:
55
+ for sf in _fields():
39
56
  for k, v in sf.items():
40
57
  print(f"{k}: {v}")
41
58
 
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keepassxc-cli
3
- Version: 0.3.0
3
+ Version: 1.1.0
4
4
  Summary: CLI for KeePassXC using the browser extension protocol with biometric unlock
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-File: LICENSE
9
- Requires-Dist: keepassxc-browser-api==0.1.3
9
+ Requires-Dist: keepassxc-browser-api==1.0.0
10
10
  Requires-Dist: pyperclip==1.8.0
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: pytest>=7.0; extra == "dev"
@@ -1,4 +1,4 @@
1
- keepassxc-browser-api==0.1.3
1
+ keepassxc-browser-api==1.0.0
2
2
  pyperclip==1.8.0
3
3
 
4
4
  [dev]
@@ -10,7 +10,7 @@ readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
12
12
  dependencies = [
13
- "keepassxc-browser-api==0.1.3",
13
+ "keepassxc-browser-api==1.0.0",
14
14
  "pyperclip==1.8.0",
15
15
  ]
16
16
 
@@ -70,11 +70,8 @@ def mock_client():
70
70
  client.test_associate.return_value = True
71
71
  client.get_logins.return_value = [make_entry()]
72
72
  client.set_login.return_value = True
73
- client.get_database_entries.return_value = [make_entry()]
74
- client.get_database_groups.return_value = [make_group()]
75
73
  client.create_group.return_value = make_group(uuid="new-uuid", name="NewGroup")
76
74
  client.get_totp.return_value = "123456"
77
75
  client.delete_entry.return_value = True
78
76
  client.lock_database.return_value = True
79
- client.generate_password.return_value = "GeneratedPass123"
80
77
  return client
@@ -7,7 +7,7 @@ from unittest.mock import MagicMock, patch
7
7
 
8
8
  import pytest
9
9
 
10
- from keepassxc_browser_api import Entry, Group, BrowserConfig, Association
10
+ from keepassxc_browser_api import Entry, BrowserConfig, Association
11
11
  from keepassxc_cli.config import CliConfig
12
12
  from keepassxc_cli.commands import (
13
13
  setup, status, show, add, edit, rm, totp, clip, lock, mkdir,
@@ -32,6 +32,7 @@ def browser_config_path(tmp_path):
32
32
  def make_args(**kwargs) -> argparse.Namespace:
33
33
  defaults = {
34
34
  "show_password": False,
35
+ "show_kph_prefix": False,
35
36
  "yes": False,
36
37
  "field": "password",
37
38
  "url": "https://example.com",
@@ -99,7 +100,7 @@ class TestStatusCommand:
99
100
 
100
101
  class TestShowCommand:
101
102
  def test_found_entries(self, mock_client, cli_config, browser_config, browser_config_path, capsys, mock_entry):
102
- entry = mock_entry()
103
+ entry = mock_entry(string_fields=[{"KPH: url": "https://github.com"}])
103
104
  mock_client.get_logins.return_value = [entry]
104
105
  args = make_args(url="https://example.com", show_password=False)
105
106
  rc = show.run(mock_client, args, cli_config, browser_config, browser_config_path)
@@ -107,6 +108,8 @@ class TestShowCommand:
107
108
  out = capsys.readouterr().out
108
109
  assert "Test Entry" in out
109
110
  assert "Password" not in out
111
+ assert "KPH: " not in out
112
+ assert "url: https://github.com" in out
110
113
 
111
114
  def test_found_entries_show_password(self, mock_client, cli_config, browser_config, browser_config_path, capsys, mock_entry):
112
115
  entry = mock_entry()
@@ -118,6 +121,14 @@ class TestShowCommand:
118
121
  assert "Test Entry" in out
119
122
  assert "Password:" in out
120
123
 
124
+ def test_found_entries_show_kph_prefix(self, mock_client, cli_config, browser_config, browser_config_path, capsys, mock_entry):
125
+ entry = mock_entry(string_fields=[{"KPH: url": "https://github.com"}])
126
+ mock_client.get_logins.return_value = [entry]
127
+ args = make_args(url="https://example.com", show_password=False, show_kph_prefix=True)
128
+ rc = show.run(mock_client, args, cli_config, browser_config, browser_config_path)
129
+ assert rc == 0
130
+ assert "KPH: url: https://github.com" in capsys.readouterr().out
131
+
121
132
  def test_no_entries(self, mock_client, cli_config, browser_config, browser_config_path, capsys):
122
133
  mock_client.get_logins.return_value = []
123
134
  args = make_args(url="https://notfound.com")
@@ -34,12 +34,20 @@ class TestPrintEntryDetail:
34
34
  assert "user@example.com" in out
35
35
  assert "Password" not in out
36
36
  assert "s3cr3t" not in out
37
+ assert "KPH: " not in out
38
+ assert "url: https://github.com" in out
37
39
 
38
40
  def test_table_format_show_password(self, capsys, sample_entry):
39
41
  print_entry_detail(sample_entry, fmt="table", show_password=True)
40
42
  out = capsys.readouterr().out
41
43
  assert "s3cr3t" in out
42
44
  assert "Password:" in out
45
+ assert "KPH: " not in out
46
+
47
+ def test_table_format_show_kph_prefix(self, capsys, sample_entry):
48
+ print_entry_detail(sample_entry, fmt="table", show_password=False, show_kph_prefix=True)
49
+ out = capsys.readouterr().out
50
+ assert "KPH: url: https://github.com" in out
43
51
 
44
52
  def test_json_format_hidden(self, capsys, sample_entry):
45
53
  print_entry_detail(sample_entry, fmt="json", show_password=False)
@@ -47,6 +55,7 @@ class TestPrintEntryDetail:
47
55
  data = json.loads(out)
48
56
  assert data["name"] == "GitHub"
49
57
  assert "password" not in data
58
+ assert data["string_fields"] == [{"url": "https://github.com"}]
50
59
 
51
60
  def test_json_format_show_password(self, capsys, sample_entry):
52
61
  print_entry_detail(sample_entry, fmt="json", show_password=True)
@@ -54,6 +63,12 @@ class TestPrintEntryDetail:
54
63
  data = json.loads(out)
55
64
  assert data["name"] == "GitHub"
56
65
  assert data["password"] == "s3cr3t"
66
+ assert data["string_fields"] == [{"url": "https://github.com"}]
67
+
68
+ def test_json_format_show_kph_prefix(self, capsys, sample_entry):
69
+ print_entry_detail(sample_entry, fmt="json", show_password=False, show_kph_prefix=True)
70
+ data = json.loads(capsys.readouterr().out)
71
+ assert data["string_fields"] == [{"KPH: url": "https://github.com"}]
57
72
 
58
73
 
59
74
  class TestPrintTotp:
File without changes
File without changes
File without changes
File without changes
File without changes