From 90ccbd24e1568086437eca973080ee35ea84f134 Mon Sep 17 00:00:00 2001 From: Matthias Valvekens Date: Fri, 29 Sep 2023 05:39:29 +0200 Subject: [PATCH] Add --resave flag to addfields subcommand ...to allow doing a full resave in order to eliminate any structural issues from the input PDF at the cost of destroying any earlier signatures. --- pyhanko/cli/commands/fields.py | 13 ++++- .../cli_tests/test_cli_field_mgmt.py | 53 ++++++++++++++++++- 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/pyhanko/cli/commands/fields.py b/pyhanko/cli/commands/fields.py index 34329907..f009df8a 100644 --- a/pyhanko/cli/commands/fields.py +++ b/pyhanko/cli/commands/fields.py @@ -5,6 +5,7 @@ from pyhanko.cli.utils import parse_field_location_spec from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter from pyhanko.pdf_utils.reader import PdfFileReader +from pyhanko.pdf_utils.writer import copy_into_new_writer from pyhanko.sign import fields __all__ = ['list_sigfields', 'add_sig_field'] @@ -44,9 +45,17 @@ def list_sigfields(infile, skip_status): required=True, help="Field specification (multiple allowed)", ) -def add_sig_field(infile, outfile, field): +@click.option( + '--resave', + is_flag=True, + help="Resave the PDF document instead of creating an incremental update", +) +def add_sig_field(infile, outfile, field, resave): with pyhanko_exception_manager(): - writer = IncrementalPdfFileWriter(infile, strict=False) + if resave: + writer = copy_into_new_writer(PdfFileReader(infile, strict=False)) + else: + writer = IncrementalPdfFileWriter(infile, strict=False) for s in field: name, spec = parse_field_location_spec(s) diff --git a/pyhanko_tests/cli_tests/test_cli_field_mgmt.py b/pyhanko_tests/cli_tests/test_cli_field_mgmt.py index 7a8d2d67..1ffa3bc9 100644 --- a/pyhanko_tests/cli_tests/test_cli_field_mgmt.py +++ b/pyhanko_tests/cli_tests/test_cli_field_mgmt.py @@ -7,7 +7,7 @@ from pyhanko.pdf_utils.reader import PdfFileReader from pyhanko.sign import PdfSignatureMetadata, sign_pdf from pyhanko_tests.cli_tests.conftest import INPUT_PATH -from pyhanko_tests.samples import MINIMAL_TWO_FIELDS, MINIMAL_TWO_PAGES +from pyhanko_tests.samples import MINIMAL, MINIMAL_TWO_FIELDS, MINIMAL_TWO_PAGES from pyhanko_tests.signing_commons import FROM_CA @@ -69,6 +69,57 @@ def test_list_empty_fields_without_status(cli_runner): assert result.output == 'Sig1\nSig2\n' +def test_cli_add_field_incremental_update_by_default(cli_runner): + with open(INPUT_PATH, 'wb') as inf: + inf.write(MINIMAL) + + output_path = 'presign.pdf' + result = cli_runner.invoke( + cli_root, + [ + 'sign', + 'addfields', + '--field', + '1/0,0,100,100/Sig1', + INPUT_PATH, + output_path, + ], + ) + assert not result.exception, result.output + + with open(output_path, 'rb') as inf: + r = PdfFileReader(inf) + name = r.root['/AcroForm']['/Fields'][0]['/T'] + assert name == 'Sig1' + assert r.xrefs.total_revisions == 2 + + +def test_cli_add_field_with_resave(cli_runner): + with open(INPUT_PATH, 'wb') as inf: + inf.write(MINIMAL) + + output_path = 'presign.pdf' + result = cli_runner.invoke( + cli_root, + [ + 'sign', + 'addfields', + '--resave', + '--field', + '1/0,0,100,100/Sig1', + INPUT_PATH, + output_path, + ], + ) + assert not result.exception, result.output + + with open(output_path, 'rb') as inf: + r = PdfFileReader(inf) + name = r.root['/AcroForm']['/Fields'][0]['/T'] + assert name == 'Sig1' + assert r.xrefs.total_revisions == 1 + + def test_cli_add_field_to_last_page(cli_runner): with open(INPUT_PATH, 'wb') as inf: inf.write(MINIMAL_TWO_PAGES)