Add --user-password, --owner-password, --bits to --encrypt

Add the command-line arguments. They don't do anything yet.
This commit is contained in:
Jay Berkenbilt 2023-12-22 16:27:56 -05:00
parent 17703a8dcd
commit 1173a0bdfc
11 changed files with 129 additions and 34 deletions

View File

@ -738,6 +738,11 @@ class Main:
if flag in expected:
options_seen.add(flag)
elif flag.startswith('__'):
# This marks a flag that has no JSON equivalent because it
# is handled in some other fashion.
options_seen.add(flag[2:])
return
elif isinstance(j, str):
if not flag.startswith('_'):
raise Exception(f'json: {flag} has a description'

View File

@ -1,17 +1,17 @@
# Generated by generate_auto_job
generate_auto_job 9abe2ec994fb98526f5e3c0c199ce2e61a868463cb522a5bc6e9730b65534187
generate_auto_job bf44181b610d335511a41b6c2b9c3497d0b023a1ca2c8e4537b34cb6262ce173
include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4
include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5
include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6
include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
job.yml 1f5db325600a763692034835117ac6b1a4b6aba8e73faa13a004ddc086834545
libqpdf/qpdf/auto_job_decl.hh 7844eba58edffb9494b19e8eca6fd59a24d6e152ca606c3b07da569f753df2da
libqpdf/qpdf/auto_job_help.hh 319c7bd0bfe2f3cb96bb16b66a9331a81b312805a64acaad54737b5623773e31
libqpdf/qpdf/auto_job_init.hh e6c09e94c92bd17e9c728b11437e3c98266c93c42c3efbce050c8d288e6b3473
job.yml 4f89fc7b622df897d30d403d8035aa36fc7de8d8c43042c736e0300d904cb05c
libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2
libqpdf/qpdf/auto_job_help.hh 788320d439519ecd284621531e96ee698965a9ad342fd423c5fb1de75d2a06b1
libqpdf/qpdf/auto_job_init.hh b4c2b3724fba61f1206fd3bae81951636852592f67a63ef9539839c2c5995065
libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297
libqpdf/qpdf/auto_job_json_init.hh 85ac7e5c66f14c767419823eac84bdea4bd72d690bfe12b533321e5708e644b7
libqpdf/qpdf/auto_job_schema.hh 5e0f5cb7d462716fe52548b2ae1a8eb6f3c900016e915140eea37f78cee45b2b
libqpdf/qpdf/auto_job_json_init.hh f5acb9aa103131cb68dec0e12c4d237a6459bdb49b24773c24f0c2724a462b8f
libqpdf/qpdf/auto_job_schema.hh b53c006fec2e75b1b73588d242d49a32f7d3db820b1541de106c5d4c27fbb4d9
manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
manual/cli.rst 4f2806f7cf77f167fd41b065a8916f02fdfaab35ad1a74587578bf2954228464
manual/cli.rst b524f96f2a6f338f3e4350703598c56ba22e8f12a8efb7a441648c6dbf0a455e

31
job.yml
View File

@ -60,6 +60,10 @@ choices:
- 1
- 2
- latest
enc_bits:
- 40
- 128
- 256
print128:
- full
- low
@ -194,8 +198,18 @@ options:
required_parameter:
password: password
- table: encryption
config: c_main
prefix: Enc
positional: true
manual:
- user-password
- owner-password
- bits
required_parameter:
user-password: user_password
owner-password: owner_password
required_choices:
bits: enc_bits
- table: 40-bit encryption
config: c_enc
config_prefix: Enc
@ -276,10 +290,14 @@ json:
# match a command-line option, and its properties and help come from
# other information known by generate_auto_job. This information is
# used to construct a "schema" (as in JSON.hh) for the json input to
# QPDFJob. The leading underscore is removed. *NOTE*: all keys are
# converted to camelCase for the schema and must appear that way
# in the user-supplied json. This makes it more convenient to
# populate JSON objects in some languages.
# QPDFJob. The leading underscore is removed. If a key starts with a
# double underscore, it corresponds to a command-line argument that
# does not have a counterpart in the JSON. This signals that the
# command-line argument was not forgotten, but it is otherwise
# ignored by the JSON. *NOTE*: all keys are converted to camelCase
# for the schema and must appear that way in the user-supplied json.
# This makes it more convenient to populate JSON objects in some
# languages.
# input
_inputFile: "input filename"
@ -316,8 +334,9 @@ json:
json-output:
remove-restrictions:
encrypt:
_user-password: "user password"
_owner-password: "owner password"
user-password:
owner-password:
__bits:
_40bit:
Enc40.annotate:
Enc40.extract:

View File

@ -203,6 +203,24 @@ ArgParser::argEncPositional(std::string const& arg)
this->c_enc = c_main->encrypt(keylen, user_password, owner_password);
}
void
ArgParser::argEncUserPassword(std::string const& arg)
{
// QXXXQ
}
void
ArgParser::argEncOwnerPassword(std::string const& arg)
{
// QXXXQ
}
void
ArgParser::argEncBits(std::string const& arg)
{
// QXXXQ
}
void
ArgParser::argPages()
{

View File

@ -109,6 +109,10 @@ Handlers::initHandlers()
#include <qpdf/auto_job_json_init.hh>
// We have `bits` in the CLI but not in the JSON. Reference this variable so it doesn't generate
// a warning.
[](char const**) {}(enc_bits_choices);
if (this->json_handlers.size() != 1) {
throw std::logic_error("QPDFJob_json: json_handlers size != 1 at end");
}

View File

@ -32,6 +32,9 @@ void argPagesPositional(std::string const&);
void argPagesPassword(std::string const&);
void argEndPages();
void argEncPositional(std::string const&);
void argEncUserPassword(std::string const&);
void argEncOwnerPassword(std::string const&);
void argEncBits(std::string const&);
void argEndEncryption();
void argEnd40BitEncryption();
void argEnd128BitEncryption();

View File

@ -152,10 +152,25 @@ ap.addOptionHelp("--encrypt", "transformation", "start encryption options", R"(-
Run qpdf --help=encryption for details.
)");
ap.addOptionHelp("--user-password", "transformation", "specify user password", R"(--user-password=user-password
Set the user password.
)");
ap.addOptionHelp("--owner-password", "transformation", "specify owner password", R"(--owner-password=owner-password
Set the owner password.
)");
ap.addOptionHelp("--bits", "transformation", "specify encryption bit depth", R"(--bits={48|128|256}
Set the encrypt bit depth. Use 256.
)");
ap.addOptionHelp("--decrypt", "transformation", "remove encryption from input file", R"(Create an unencrypted output file even if the input file was
encrypted. Normally qpdf preserves whatever encryption was
present on the input file. This option overrides that behavior.
)");
}
static void add_help_3(QPDFArgParser& ap)
{
ap.addOptionHelp("--remove-restrictions", "transformation", "remove security restrictions from input file", R"(Remove restrictions associated with digitally signed PDF files.
This may be combined with --decrypt to allow free editing of
previously signed/encrypted files. This option invalidates the
@ -172,9 +187,6 @@ ap.addOptionHelp("--encryption-file-password", "transformation", "supply passwor
If the file named in --copy-encryption requires a password, use
this option to supply the password.
)");
}
static void add_help_3(QPDFArgParser& ap)
{
ap.addOptionHelp("--qdf", "transformation", "enable viewing PDF code in a text editor", R"(Create a PDF file suitable for viewing in a text editor and even
editing. This is for editing the PDF code, not the page contents.
All streams that can be uncompressed are uncompressed, and
@ -270,6 +282,9 @@ ap.addOptionHelp("--ii-min-bytes", "transformation", "set minimum size for --ext
Don't externalize inline images smaller than this size. The
default is 1,024. Use 0 for no minimum.
)");
}
static void add_help_4(QPDFArgParser& ap)
{
ap.addOptionHelp("--min-version", "transformation", "set minimum PDF version", R"(--min-version=version
Force the PDF version of the output to be at least the specified
@ -297,9 +312,6 @@ resulting set of pages, where :odd starts with the first page and
:even starts with the second page. These are odd and even pages
from the resulting set, not based on the original page numbers.
)");
}
static void add_help_4(QPDFArgParser& ap)
{
ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of
the PDF, causing the PDF to render differently from the original.
)");
@ -392,6 +404,9 @@ ap.addOptionHelp("--keep-inline-images", "modification", "exclude inline images
)");
ap.addOptionHelp("--remove-page-labels", "modification", "remove explicit page numbers", R"(Exclude page labels (explicit page numbers) from the output file.
)");
}
static void add_help_5(QPDFArgParser& ap)
{
ap.addHelpTopic("encryption", "create encrypted files", R"(Create encrypted files. Usage:
--encrypt user-password owner-password key-length [options] --
@ -467,9 +482,6 @@ and filling in form fields. For 128-bit and 256-bit encryption,
this also enables editing, creating, and deleting form fields
unless --modify-other=n or --modify=none is also specified.
)");
}
static void add_help_5(QPDFArgParser& ap)
{
ap.addOptionHelp("--assemble", "encryption", "restrict document assembly", R"(--assemble=[y|n]
Enable/disable document assembly (rotation and reordering of
@ -628,6 +640,9 @@ Specify pages from the overlay/underlay that are repeated after
"from" pages have been exhausted. See qpdf --help=page-ranges
for help with the page range syntax.
)");
}
static void add_help_6(QPDFArgParser& ap)
{
ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known
as attachments) and to copy attachments from other files. See help
on individual options for details. Run qpdf --help=add-attachment
@ -645,9 +660,6 @@ The --copy-attachments-from flag and its options may be repeated
to copy attachments from multiple files. Run
qpdf --help=copy-attachments for details.
)");
}
static void add_help_6(QPDFArgParser& ap)
{
ap.addOptionHelp("--remove-attachment", "attachments", "remove an embedded file", R"(--remove-attachment=key
Remove an embedded file using its key. Get the key with
@ -746,6 +758,9 @@ of the actual PDF page content or semantic correctness of the
PDF file. It merely checks that the PDF file is syntactically
valid. See also qpdf --help=exit-status.
)");
}
static void add_help_7(QPDFArgParser& ap)
{
ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's
user password if the owner password is given and the file was
encrypted using older encryption formats that allow user
@ -757,9 +772,6 @@ underlying encryption key to be displayed.
ap.addOptionHelp("--check-linearization", "inspection", "check linearization tables", R"(Check to see whether a file is linearized and, if so, whether
the linearization hint tables are correct.
)");
}
static void add_help_7(QPDFArgParser& ap)
{
ap.addOptionHelp("--show-linearization", "inspection", "show linearization hint tables", R"(Check and display all data in the linearization hint tables.
)");
ap.addOptionHelp("--show-xref", "inspection", "show cross reference data", R"(Show the contents of the cross-reference table or stream (object
@ -840,6 +852,9 @@ object number. The prefix can be overridden with
when --json-output is specified, in which case the default is
"inline".
)");
}
static void add_help_8(QPDFArgParser& ap)
{
ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix
When used with --json-stream-data=file, --json-stream-data=file-prefix
@ -860,9 +875,6 @@ ap.addOptionHelp("--json-input", "json", "input file is qpdf JSON", R"(Treat the
"qpdf JSON Format" section of the manual for information about
how to use this option.
)");
}
static void add_help_8(QPDFArgParser& ap)
{
ap.addOptionHelp("--update-from-json", "json", "update a PDF from qpdf JSON", R"(--update-from-json=qpdf-json-file
Update a PDF file from a JSON file. Please see the "qpdf JSON"

View File

@ -23,6 +23,7 @@ static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "
static char const* json_output_choices[] = {"2", "latest", 0};
static char const* json_stream_data_choices[] = {"none", "inline", "file", 0};
static char const* json_version_choices[] = {"1", "2", "latest", 0};
static char const* enc_bits_choices[] = {"40", "128", "256", 0};
static char const* print128_choices[] = {"full", "low", "none", 0};
static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
@ -128,6 +129,9 @@ this->ap.addPositional(p(&ArgParser::argPagesPositional));
this->ap.addRequiredParameter("password", p(&ArgParser::argPagesPassword), "password");
this->ap.registerOptionTable("encryption", b(&ArgParser::argEndEncryption));
this->ap.addPositional(p(&ArgParser::argEncPositional));
this->ap.addRequiredParameter("user-password", p(&ArgParser::argEncUserPassword), "user_password");
this->ap.addRequiredParameter("owner-password", p(&ArgParser::argEncOwnerPassword), "owner_password");
this->ap.addChoices("bits", p(&ArgParser::argEncBits), true, enc_bits_choices);
this->ap.registerOptionTable("40-bit encryption", b(&ArgParser::argEnd40BitEncryption));
this->ap.addChoices("extract", [this](std::string const& x){c_enc->extract(x);}, true, yn_choices);
this->ap.addChoices("annotate", [this](std::string const& x){c_enc->annotate(x);}, true, yn_choices);

View File

@ -16,6 +16,7 @@ static char const* json_key_choices[] = {"acroform", "attachments", "encrypt", "
static char const* json_output_choices[] = {"2", "latest", 0};
static char const* json_stream_data_choices[] = {"none", "inline", "file", 0};
static char const* json_version_choices[] = {"1", "2", "latest", 0};
static char const* enc_bits_choices[] = {"40", "128", "256", 0};
static char const* print128_choices[] = {"full", "low", "none", 0};
static char const* modify128_choices[] = {"all", "annotate", "form", "assembly", "none", 0};
@ -120,6 +121,8 @@ popHandler(); // key: userPassword
pushKey("ownerPassword");
setupEncryptOwnerPassword();
popHandler(); // key: ownerPassword
pushKey("Bits");
popHandler(); // key: Bits
pushKey("40bit");
beginDict(bindJSON(&Handlers::beginEncrypt40bit), bindBare(&Handlers::endEncrypt40bit)); // .encrypt.40bit
pushKey("annotate");

View File

@ -31,8 +31,9 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({
"jsonOutput": "apply defaults for JSON serialization",
"removeRestrictions": "remove security restrictions from input file",
"encrypt": {
"userPassword": "user password",
"ownerPassword": "owner password",
"userPassword": "specify user password",
"ownerPassword": "specify owner password",
"Bits": null,
"40bit": {
"annotate": "restrict document annotation",
"extract": "restrict text/graphic extraction",

View File

@ -723,6 +723,32 @@ Related Options
This flag starts encryption options, used to create encrypted
files. Please see :ref:`encryption-options` for details.
.. qpdf:option:: --user-password=user-password
.. help: specify user password
Set the user password.
Set the user password for the encrypted file.
.. qpdf:option:: --owner-password=owner-password
.. help: specify owner password
Set the owner password.
Set the owner password for the encrypted file.
.. qpdf:option:: --bits={48|128|256}
.. help: specify encryption bit depth
Set the encrypt bit depth. Use 256.
Set the bit depth for encrypted files. You should always use
``--bits=256`` unless you have a strong reason to create a file
with weaker encryption.
.. qpdf:option:: --decrypt
.. help: remove encryption from input file