Commit 408c72e81682d71e15ef293790913c17ba5e0ec1

Authored by m-holger
1 parent 5dbcd9c9

Fix password handling in QPDFJob to allow multiple specifications and add tests

Fixes #1659
libqpdf/QPDFJob.cc
@@ -2505,9 +2505,13 @@ void @@ -2505,9 +2505,13 @@ void
2505 QPDFJob::Selection::password(std::string password) 2505 QPDFJob::Selection::password(std::string password)
2506 { 2506 {
2507 auto& in = input(); 2507 auto& in = input();
2508 - if (!in.password.empty()) { 2508 + if (password_provided) {
2509 usage("--password already specified for this file"); 2509 usage("--password already specified for this file");
2510 } 2510 }
  2511 + if (!(in.password.empty() || in.password == password)) {
  2512 + usage("different --password already specified for this file");
  2513 + }
  2514 + password_provided = true;
2511 in.password = password; 2515 in.password = password;
2512 } 2516 }
2513 2517
libqpdf/qpdf/QPDFJob_private.hh
@@ -29,6 +29,7 @@ struct QPDFJob::Selection @@ -29,6 +29,7 @@ struct QPDFJob::Selection
29 std::pair<const std::string, QPDFJob::Input>* in_entry{nullptr}; 29 std::pair<const std::string, QPDFJob::Input>* in_entry{nullptr};
30 std::string range; // An empty range means all pages. 30 std::string range; // An empty range means all pages.
31 std::vector<int> selected_pages; 31 std::vector<int> selected_pages;
  32 + bool password_provided{false};
32 }; 33 };
33 34
34 // A single input PDF. 35 // A single input PDF.
manual/release-notes.rst
@@ -13,8 +13,13 @@ more detail. @@ -13,8 +13,13 @@ more detail.
13 13
14 .. x.y.z: not yet released 14 .. x.y.z: not yet released
15 15
16 -  
17 12.3.2: not yet released 16 12.3.2: not yet released
  17 + - Bug fixes
  18 +
  19 + - Fix bug introduced in 12.3.0. If the :qpdf:ref:`--password` was specified
  20 + for the same file multiple times a usage error was thrown. Specifying
  21 + the the password multiple times is common within the :qpdf:ref:`--pages`
  22 + option when using the QPDFJob interface.
18 23
19 12.3.1: January 19, 2026 24 12.3.1: January 19, 2026
20 - Bug fixes 25 - Bug fixes
qpdf/qtest/arg-parsing.test
@@ -15,7 +15,7 @@ cleanup(); @@ -15,7 +15,7 @@ cleanup();
15 15
16 my $td = new TestDriver('arg-parsing'); 16 my $td = new TestDriver('arg-parsing');
17 17
18 -my $n_tests = 33; 18 +my $n_tests = 35;
19 19
20 $td->runtest("required argument", 20 $td->runtest("required argument",
21 {$td->COMMAND => "qpdf --password minimal.pdf"}, 21 {$td->COMMAND => "qpdf --password minimal.pdf"},
@@ -88,6 +88,16 @@ $td-&gt;runtest(&quot;duplicated pages password&quot;, @@ -88,6 +88,16 @@ $td-&gt;runtest(&quot;duplicated pages password&quot;,
88 {$td->REGEXP => ".*password already specified.*", 88 {$td->REGEXP => ".*password already specified.*",
89 $td->EXIT_STATUS => 2}, 89 $td->EXIT_STATUS => 2},
90 $td->NORMALIZE_NEWLINES); 90 $td->NORMALIZE_NEWLINES);
  91 +$td->runtest("inconsistent pages passwords",
  92 + {$td->COMMAND => "qpdf --pages . --password=z --range=1 . --password=y --range=2 --"},
  93 + {$td->REGEXP => ".*different --password already specified.*",
  94 + $td->EXIT_STATUS => 2},
  95 + $td->NORMALIZE_NEWLINES);
  96 +$td->runtest("consistent pages passwords",
  97 + {$td->COMMAND => "qpdf --pages . --password=z --range=1 . --password=z --range=2 --"},
  98 + {$td->REGEXP => ".*an input file name is required.*",
  99 + $td->EXIT_STATUS => 2},
  100 + $td->NORMALIZE_NEWLINES);
91 $td->runtest("v1-only objects json-key", 101 $td->runtest("v1-only objects json-key",
92 {$td->COMMAND => "qpdf --json=2 --json-key=objects minimal.pdf"}, 102 {$td->COMMAND => "qpdf --json=2 --json-key=objects minimal.pdf"},
93 {$td->REGEXP => ".*\"objects\" and \"objectinfo\" are " . 103 {$td->REGEXP => ".*\"objects\" and \"objectinfo\" are " .