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.
- {keepassxc_cli-0.3.0/keepassxc_cli.egg-info → keepassxc_cli-1.1.0}/PKG-INFO +2 -2
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/show.py +2 -1
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/output.py +20 -3
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0/keepassxc_cli.egg-info}/PKG-INFO +2 -2
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/requires.txt +1 -1
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/pyproject.toml +1 -1
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/conftest.py +0 -3
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/test_commands.py +13 -2
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/tests/test_output.py +15 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/auto-merge-dependabot.yml +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/auto-release.yml +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/lint_and_test.yml +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.github/workflows/pypi.yml +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/.gitignore +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/CLAUDE.md +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/LICENSE +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/README.md +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/__init__.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/__main__.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/__init__.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/add.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/clip.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/edit.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/lock.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/mkdir.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/rm.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/setup.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/status.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/commands/totp.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli/config.py +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/SOURCES.txt +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/dependency_links.txt +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/entry_points.txt +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/keepassxc_cli.egg-info/top_level.txt +0 -0
- {keepassxc_cli-0.3.0 → keepassxc_cli-1.1.0}/setup.cfg +0 -0
- {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:
|
|
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.
|
|
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
|
-
|
|
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":
|
|
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
|
|
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:
|
|
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.
|
|
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"
|
|
@@ -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,
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|