pyhanko-cli 0.1.0__tar.gz → 0.1.2__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.
- {pyhanko_cli-0.1.0/src/pyhanko_cli.egg-info → pyhanko_cli-0.1.2}/PKG-INFO +3 -3
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/pyproject.toml +5 -9
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/stamp.py +27 -2
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/validation/validate.py +10 -2
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/runtime.py +1 -4
- pyhanko_cli-0.1.2/src/pyhanko/cli/version.py +2 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2/src/pyhanko_cli.egg-info}/PKG-INFO +3 -3
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko_cli.egg-info/requires.txt +2 -2
- pyhanko_cli-0.1.0/src/pyhanko/cli/version.py +0 -2
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/LICENSE +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/MANIFEST.in +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/README.md +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/setup.cfg +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/__main__.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/__init__.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/_ctx.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/_root.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/_trust.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/__init__.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/crypt.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/fields.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/signing/__init__.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/signing/pkcs11_cli.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/signing/plugin.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/signing/simple.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/signing/utils.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/validation/__init__.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/commands/validation/ltv.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/config.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/plugin_api.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/py.typed +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko/cli/utils.py +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko_cli.egg-info/SOURCES.txt +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko_cli.egg-info/dependency_links.txt +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko_cli.egg-info/entry_points.txt +0 -0
- {pyhanko_cli-0.1.0 → pyhanko_cli-0.1.2}/src/pyhanko_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyhanko-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: CLI tools for stamping and signing PDF files
|
|
5
5
|
Author-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
6
6
|
Maintainer-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
@@ -27,9 +27,9 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: asn1crypto>=1.5.1
|
|
29
29
|
Requires-Dist: tzlocal>=4.3
|
|
30
|
-
Requires-Dist: pyhanko<0.30,>=0.29.
|
|
30
|
+
Requires-Dist: pyhanko<0.30,>=0.29.1
|
|
31
31
|
Requires-Dist: pyhanko-certvalidator<0.28,>=0.27.0
|
|
32
|
-
Requires-Dist: click
|
|
32
|
+
Requires-Dist: click!=8.2.0,>=8.1.3
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
35
|
The lack of open-source CLI tooling to handle digitally signing and stamping PDF files was bothering me, so I went ahead and rolled my own.
|
|
@@ -33,11 +33,11 @@ requires-python = ">=3.9"
|
|
|
33
33
|
dependencies = [
|
|
34
34
|
"asn1crypto>=1.5.1",
|
|
35
35
|
"tzlocal>=4.3",
|
|
36
|
-
"pyhanko>=0.29.
|
|
36
|
+
"pyhanko>=0.29.1,<0.30",
|
|
37
37
|
"pyhanko-certvalidator>=0.27.0,<0.28",
|
|
38
|
-
"click>=8.1.3
|
|
38
|
+
"click>=8.1.3,!=8.2.0",
|
|
39
39
|
]
|
|
40
|
-
version = "0.1.
|
|
40
|
+
version = "0.1.2"
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
[project.readme]
|
|
@@ -57,7 +57,7 @@ testing-base = [
|
|
|
57
57
|
"pytest>=6.1.1",
|
|
58
58
|
"requests-mock>=1.8.0",
|
|
59
59
|
"freezegun>=1.1.0",
|
|
60
|
-
"certomancer>=0.
|
|
60
|
+
"certomancer>=0.13.0,<0.14",
|
|
61
61
|
"pytest-cov>=4.0,<6.2",
|
|
62
62
|
"pytest-asyncio==0.24.0;python_version<\"3.9\"",
|
|
63
63
|
"pytest-asyncio==0.26.0;python_version>=\"3.9\"",
|
|
@@ -65,7 +65,7 @@ testing-base = [
|
|
|
65
65
|
]
|
|
66
66
|
testing = [
|
|
67
67
|
{include-group = "testing-base"},
|
|
68
|
-
"aiohttp>=3.9,<3.
|
|
68
|
+
"aiohttp>=3.9,<3.13",
|
|
69
69
|
"pytest-aiohttp>=1.0.4,<1.2.0",
|
|
70
70
|
"pyhanko[pkcs11,opentype,async_http,image-support,qr]"
|
|
71
71
|
]
|
|
@@ -83,10 +83,6 @@ pyhanko = ["py.typed"]
|
|
|
83
83
|
|
|
84
84
|
[tool.pytest.ini_options]
|
|
85
85
|
pythonpath = ["src"]
|
|
86
|
-
log_format = "%(asctime)s %(levelname)s %(message)s"
|
|
87
|
-
log_date_format = "%Y-%m-%d %H:%M:%S"
|
|
88
|
-
log_cli = true
|
|
89
|
-
log_cli_level = "INFO"
|
|
90
86
|
asyncio_mode = "strict"
|
|
91
87
|
asyncio_default_fixture_loop_scope="function"
|
|
92
88
|
markers = [
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from typing import Optional
|
|
2
3
|
|
|
3
4
|
import click
|
|
@@ -39,7 +40,7 @@ def select_style(ctx: click.Context, style_name: str, url: str):
|
|
|
39
40
|
return style
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
PARAM_REGEX = re.compile("([a-zA-Z0-9_]+):(.*)")
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
@cli_root.command(help='stamp PDF files', name='stamp')
|
|
@@ -67,6 +68,13 @@ def select_style(ctx: click.Context, style_name: str, url: str):
|
|
|
67
68
|
required=False,
|
|
68
69
|
type=str,
|
|
69
70
|
)
|
|
71
|
+
@click.option(
|
|
72
|
+
'--text-param',
|
|
73
|
+
help='parameter to interpolate in the stamp text (multiple allowed)',
|
|
74
|
+
required=False,
|
|
75
|
+
multiple=True,
|
|
76
|
+
type=str,
|
|
77
|
+
)
|
|
70
78
|
@click.pass_context
|
|
71
79
|
def stamp(
|
|
72
80
|
ctx,
|
|
@@ -77,10 +85,20 @@ def stamp(
|
|
|
77
85
|
style_name: str,
|
|
78
86
|
page: int,
|
|
79
87
|
stamp_url: str,
|
|
88
|
+
text_param: list,
|
|
80
89
|
):
|
|
81
90
|
cli_config: Optional[CLIConfig] = ctx.obj.config
|
|
82
91
|
if cli_config is None:
|
|
83
92
|
raise click.ClickException(_CONFIG_REQUIRED_MSG)
|
|
93
|
+
text_params = {}
|
|
94
|
+
for param in text_param:
|
|
95
|
+
m = PARAM_REGEX.match(param)
|
|
96
|
+
if not m:
|
|
97
|
+
raise click.ClickException(
|
|
98
|
+
f"--text-param must be of the form "
|
|
99
|
+
f"<name>:<value>, not f{param!r}"
|
|
100
|
+
)
|
|
101
|
+
text_params[m.group(1)] = m.group(2)
|
|
84
102
|
with pyhanko_exception_manager():
|
|
85
103
|
stamp_style = select_style(ctx, style_name, stamp_url)
|
|
86
104
|
page_ix = _index_page(page)
|
|
@@ -93,8 +111,15 @@ def stamp(
|
|
|
93
111
|
x=x,
|
|
94
112
|
y=y,
|
|
95
113
|
url=stamp_url,
|
|
114
|
+
text_params=text_params,
|
|
96
115
|
)
|
|
97
116
|
else:
|
|
98
117
|
text_stamp_file(
|
|
99
|
-
infile,
|
|
118
|
+
infile,
|
|
119
|
+
outfile,
|
|
120
|
+
stamp_style,
|
|
121
|
+
dest_page=page_ix,
|
|
122
|
+
x=x,
|
|
123
|
+
y=y,
|
|
124
|
+
text_params=text_params,
|
|
100
125
|
)
|
|
@@ -310,9 +310,17 @@ def validate_signatures(
|
|
|
310
310
|
r = PdfFileReader(infile)
|
|
311
311
|
sh = r.security_handler
|
|
312
312
|
if isinstance(sh, crypt.StandardSecurityHandler):
|
|
313
|
+
auth_result = None
|
|
313
314
|
if password is None:
|
|
314
|
-
|
|
315
|
-
|
|
315
|
+
# attempt the empty user password first--validation is a read-only
|
|
316
|
+
# operation, so this is in line with expected UX in other viewers.
|
|
317
|
+
empty_auth_result = r.decrypt("")
|
|
318
|
+
if empty_auth_result.status == crypt.AuthStatus.FAILED:
|
|
319
|
+
password = getpass.getpass(prompt='File password: ')
|
|
320
|
+
else:
|
|
321
|
+
auth_result = empty_auth_result
|
|
322
|
+
if not auth_result:
|
|
323
|
+
auth_result = r.decrypt(password)
|
|
316
324
|
if auth_result.status == crypt.AuthStatus.FAILED:
|
|
317
325
|
raise click.ClickException("Password didn't match.")
|
|
318
326
|
elif sh is not None:
|
|
@@ -25,7 +25,7 @@ def logging_setup(log_configs, verbose: bool):
|
|
|
25
25
|
cur_logger.setLevel(log_config.level)
|
|
26
26
|
handler: logging.StreamHandler
|
|
27
27
|
if isinstance(log_config.output, StdLogOutput):
|
|
28
|
-
if
|
|
28
|
+
if log_config.output == StdLogOutput.STDOUT:
|
|
29
29
|
handler = logging.StreamHandler(sys.stdout)
|
|
30
30
|
else:
|
|
31
31
|
handler = logging.StreamHandler()
|
|
@@ -59,9 +59,6 @@ def pyhanko_exception_manager():
|
|
|
59
59
|
except misc.PdfReadError as e:
|
|
60
60
|
exception = e
|
|
61
61
|
msg = f"Failed to read PDF file: {e.msg}"
|
|
62
|
-
except misc.PdfWriteError as e:
|
|
63
|
-
exception = e
|
|
64
|
-
msg = f"Failed to write PDF file: {e.msg}"
|
|
65
62
|
except SigningError as e:
|
|
66
63
|
exception = e
|
|
67
64
|
msg = f"Error raised while producing signed file: {e.msg}"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyhanko-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: CLI tools for stamping and signing PDF files
|
|
5
5
|
Author-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
6
6
|
Maintainer-email: Matthias Valvekens <dev@mvalvekens.be>
|
|
@@ -27,9 +27,9 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
License-File: LICENSE
|
|
28
28
|
Requires-Dist: asn1crypto>=1.5.1
|
|
29
29
|
Requires-Dist: tzlocal>=4.3
|
|
30
|
-
Requires-Dist: pyhanko<0.30,>=0.29.
|
|
30
|
+
Requires-Dist: pyhanko<0.30,>=0.29.1
|
|
31
31
|
Requires-Dist: pyhanko-certvalidator<0.28,>=0.27.0
|
|
32
|
-
Requires-Dist: click
|
|
32
|
+
Requires-Dist: click!=8.2.0,>=8.1.3
|
|
33
33
|
Dynamic: license-file
|
|
34
34
|
|
|
35
35
|
The lack of open-source CLI tooling to handle digitally signing and stamping PDF files was bothering me, so I went ahead and rolled my own.
|
|
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
|