From bde98044f4acd5ce0e1965ad28a6854c31aa29a1 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 29 Jul 2012 13:22:37 -0400 Subject: Improve password handling Use --encryption-file-password, if given, in addition to --password as a source for passwords for files specified in --pages. --- manual/qpdf-manual.xml | 24 ++++++++++-------------- qpdf/qpdf.cc | 30 +++++++++++++++++++----------- qpdf/qpdf.testcov | 3 ++- qpdf/qtest/qpdf.test | 11 ++++++++++- qpdf/qtest/qpdf/pages-copy-encryption.pdf | Bin 0 -> 1319 bytes 5 files changed, 41 insertions(+), 27 deletions(-) create mode 100644 qpdf/qtest/qpdf/pages-copy-encryption.pdf diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index da3ee833..1b87fdf9 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -586,20 +586,16 @@ make For each file that pages should be taken from, specify the file, a - password needed to open the file (if needed), and a page range. - If the primary input file file requires a password, that password - must be specified outside the option and - does not need to be repeated inside the . - The same file can be repeated multiple times. If a file that is - repeated has a password, the password only has to be given the - first time. All non-page data (info, outlines, page numbers, - etc.) are taken from the primary input file. To discard these, - use as the primary input. One subtlety - about specifying passwords is that specifying a password as - doesn't prevent you - from having to repeat that password of that is also one of the - input files. If in doubt, it's never an error to specify the - password multiple times. + password needed to open the file (if any), and a page range. The + password needs to be given only once per file. If any of the + input files are the same as the primary input file or the file + used to copy encryption parameters (if specified), you do not need + to repeat the password here. The same file can be repeated + multiple times. If a file that is repeated has a password, the + password only has to be given the first time. All non-page data + (info, outlines, page numbers, etc.) are taken from the primary + input file. To discard these, use as the + primary input. It is not presently possible to specify the same page from the diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index e1522752..2835a966 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -152,13 +152,14 @@ starting point, but its pages are replaced with pages as specified.\n\ --pages file [ --password=password ] page-range ... --\n\ \n\ For each file that pages should be taken from, specify the file, a\n\ -password needed to open the file (if needed), and a page range. The\n\ -password needs to be given only once per file. If the input file file\n\ -requires a password, that password must be specified outside the\n\ ---pages option and does not need to be repeated. The same file can be\n\ -repeated multiple times. All non-page data (info, outlines, page numbers,\n\ -etc. are taken from the primary input file. To discard this, use --empty\n\ -as the primary input.\n\ +password needed to open the file (if any), and a page range. The\n\ +password needs to be given only once per file. If any of the input\n\ +files are the same as the primary input file or the file used to copy\n\ +encryption parameters (if specified), you do not need to repeat the\n\ +password here. The same file can be repeated multiple times. All\n\ +non-page data (info, outlines, page numbers, etc. are taken from the\n\ +primary input file. To discard this, use --empty as the primary\n\ +input.\n\ \n\ The page range is a set of numbers separated by commas, ranges of\n\ numbers separated dashes, or combinations of those. The character\n\ @@ -880,13 +881,13 @@ int main(int argc, char* argv[]) exit(0); } - char const* password = ""; + char const* password = 0; bool linearize = false; bool decrypt = false; bool copy_encryption = false; char const* encryption_file = 0; - char const* encryption_file_password = ""; + char const* encryption_file_password = 0; bool encrypt = false; std::string user_password; @@ -1282,7 +1283,7 @@ int main(int argc, char* argv[]) if (filter && (! obj.pipeStreamData(0, true, false, false))) { - QTC::TC("qpdf", "unable to filter"); + QTC::TC("qpdf", "qpdf unable to filter"); std::cerr << "Unable to filter stream data." << std::endl; exit(EXIT_ERROR); @@ -1445,8 +1446,15 @@ int main(int argc, char* argv[]) PointerHolder qpdf_ph = new QPDF(); page_heap.push_back(qpdf_ph); QPDF* qpdf = qpdf_ph.getPointer(); + char const* password = page_spec.password; + if (encryption_file && (password == 0) && + (page_spec.filename == encryption_file)) + { + QTC::TC("qpdf", "qpdf pages encryption password"); + password = encryption_file_password; + } qpdf->processFile( - page_spec.filename.c_str(), page_spec.password); + page_spec.filename.c_str(), password); page_spec_qpdfs[page_spec.filename] = qpdf; } diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index ae771c6d..fd120839 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -113,7 +113,7 @@ QPDFObjectHandle indirect to unknown 0 QPDF_Stream pipeStreamData with null pipeline 0 QPDFWriter not recompressing /FlateDecode 0 QPDF_encryption xref stream from encrypted file 0 -unable to filter 0 +qpdf unable to filter 0 QPDF_String non-trivial UTF-16 0 QPDF xref overwrite object 0 QPDF decoding error warning 0 @@ -237,3 +237,4 @@ QPDFWriter foreign object 0 QPDFWriter copy use_aes 1 QPDFObjectHandle indirect without context 0 QPDFObjectHandle trailing data in parse 0 +qpdf pages encryption password 0 diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test index 8cdc82a7..da318491 100644 --- a/qpdf/qtest/qpdf.test +++ b/qpdf/qtest/qpdf.test @@ -424,7 +424,7 @@ foreach my $d (@nrange_tests) # ---------- $td->notify("--- Merging and Splitting ---"); -$n_tests += 4; +$n_tests += 6; # Select pages from the same file multiple times including selecting # twice from an encrypted file and specifying the password only the @@ -460,6 +460,15 @@ $td->runtest("merge three files", $td->runtest("check output", {$td->FILE => "a.pdf"}, {$td->FILE => "merge-three-files-2.pdf"}); +$td->runtest("avoid respecification of password", + {$td->COMMAND => + "qpdf --empty a.pdf --copy-encryption=20-pages.pdf" . + " --encryption-file-password=user" . + " --pages 20-pages.pdf 1,z -- --static-id"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "pages-copy-encryption.pdf"}); # ---------- $td->notify("--- PDF From Scratch ---"); $n_tests += 2; diff --git a/qpdf/qtest/qpdf/pages-copy-encryption.pdf b/qpdf/qtest/qpdf/pages-copy-encryption.pdf new file mode 100644 index 00000000..40280642 Binary files /dev/null and b/qpdf/qtest/qpdf/pages-copy-encryption.pdf differ -- cgit v1.2.3-54-g00ecf