From d4f2eaace819adf32ad8ef80aaf1d69d3e0a4e3d Mon Sep 17 00:00:00 2001 From: wizonesolutions <wizonesolutions@739994.no-reply.drupal.org> Date: Mon, 5 Mar 2018 17:26:08 -0500 Subject: [PATCH] Issue #2948793 by wizonesolutions, noahzenzen, Liam Morland: Support PDF security in pdftk --- fillpdf.admin.inc | 60 ++++++++++++++++++++++++++++++++++++++++++++++- fillpdf.install | 36 ++++++++++++++++++++++++++++ fillpdf.module | 22 +++++++++++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/fillpdf.admin.inc b/fillpdf.admin.inc index ab6e39d..25e7e68 100644 --- a/fillpdf.admin.inc +++ b/fillpdf.admin.inc @@ -399,7 +399,7 @@ function fillpdf_form_edit($form, &$form_state, $fid) { '#type' => 'fieldset', '#title' => t('Additional PDF settings'), '#collapsible' => TRUE, - '#collapsed' => !($pdf_form->destination_path || $pdf_form->replacements), + '#collapsed' => !($pdf_form->destination_path || $pdf_form->replacements || $pdf_form->destination_redirect || $pdf_form->pdftk_encryption || $pdf_form->owner_password || $pdf_form->user_password), ); $form['extra']['destination_path'] = array( '#type' => 'textfield', @@ -449,6 +449,56 @@ function fillpdf_form_edit($form, &$form_state, $fid) { '#default_value' => $pdf_form->replacements, ); + $form['extra']['security'] = array( + '#type' => 'fieldset', + '#title' => t('PDF Security (currently only works with pdftk)'), + ); + + $security_form = &$form['extra']['security']; + $security_form['pdftk_encryption'] = array( + '#type' => 'radios', + '#title' => t('PDFtk Encryption Strength'), + '#description' => t("Select the type of PDFtk encryption you'd like to use. You should choose 128-bit unless you know otherwise."), + '#options' => array( + '' => t('No encryption (Default)'), + 'encrypt_128bit' => t('128-bit encryption (Recommended)'), + 'encrypt_40bit' => t('40-bit encryption'), + ), + '#default_value' => $pdf_form->pdftk_encryption, + ); + + $security_form['permissions'] = array( + '#type' => 'checkboxes', + '#title' => t('User Permissions'), + '#description' => t('Choose the permissions the user should have for the encrypted PDF. If they enter the Owner Password, they will be able to unlock it. <strong>If you do not specify any permissions, then none of these operations will be allowed.</strong>'), + '#options' => array( + 'Printing' => t('Printing (Top Quality Printing)'), + 'DegradedPrinting' => t('DegradedPrinting (Lower Quality Printing)'), + 'ModifyContents' => t('ModifyContents (Also allows <em>Assembly</em>)'), + 'Assembly' => t('Assembly'), + 'CopyContents' => t('CopyContents (Also allows <em>ScreenReaders</em>)'), + 'ScreenReaders' => t('ScreenReaders'), + 'ModifyAnnotations' => t('ModifyAnnotations (Also allows <em>FillIn</em>)'), + 'FillIn' => t('FillIn'), + 'AllFeatures' => t('AllFeatures (Allows the user to perform all of the above, and top quality printing.)'), + ), + '#default_value' => $pdf_form->permissions, + ); + + $security_form['owner_password'] = array( + '#type' => 'textfield', + '#title' => t('Owner Password'), + '#description' => t('Required for encryption. Enter the decryption password for the PDF. This password allows PDF security settings to be changed. If you configure encryption and permissions but leave this blank, then anyone will be able to change the security settings.'), + '#default_value' => $pdf_form->owner_password, + ); + + $security_form['user_password'] = array( + '#type' => 'textfield', + '#title' => t('User Password'), + '#description' => t("Optional. If you want to restrict the opening of this PDF to those with a password, enter one here."), + '#default_value' => $pdf_form->user_password, + ); + $form['submit'] = array( '#type' => 'submit', '#value' => t('Update'), @@ -534,6 +584,10 @@ function fillpdf_form_edit_validate($form, &$form_state) { form_set_error('destination_path', t('You have chosen to use <em>Private files</em> for storage. Your destination path must be a subdirectory of the <em>fillpdf</em> directory and cannot be absolute.')); } + + // Consolidate permissions into a string. + $filtered_permissions = array_filter($form_state['values']['permissions']); + $form_state['values']['permissions'] = implode(',', array_keys($filtered_permissions)); } /** @@ -554,6 +608,10 @@ function fillpdf_form_edit_submit($form, &$form_state) { 'destination_redirect' => $form_state['values']['destination_redirect'], 'admin_title' => $form_state['values']['admin_title'], 'scheme' => $form_state['values']['scheme'], + 'pdftk_encryption' => $form_state['values']['pdftk_encryption'], + 'permissions' => $form_state['values']['permissions'], + 'owner_password' => $form_state['values']['owner_password'], + 'user_password' => $form_state['values']['user_password'], )) ->condition('fid', $form['#pdf_form']->fid) ->execute(); diff --git a/fillpdf.install b/fillpdf.install index 22dd59a..e263ea1 100644 --- a/fillpdf.install +++ b/fillpdf.install @@ -52,6 +52,22 @@ function fillpdf_schema() { 'type' => 'varchar', 'length' => 64, ), + 'pdftk_encryption' => array( + 'type' => 'varchar', + 'length' => 64, + ), + 'owner_password' => array( + 'type' => 'varchar', + 'length' => 255, + ), + 'user_password' => array( + 'type' => 'varchar', + 'length' => 255, + ), + 'permissions' => array( + 'type' => 'varchar', + 'length' => 512, + ), ), 'primary key' => array('fid'), ); @@ -329,6 +345,26 @@ function fillpdf_update_7106() { drupal_set_message(t('Private file metadata migrated to the new format.')); } +/** + * Add new PDF security-related fields for PDFtk. + */ +function fillpdf_update_7107() { + $schema = drupal_get_schema_unprocessed('fillpdf', 'fillpdf_forms'); + + if (!db_field_exists('fillpdf_forms', 'pdftk_encryption')) { + db_add_field('fillpdf_forms', 'pdftk_encryption', $schema['fields']['pdftk_encryption']); + } + if (!db_field_exists('fillpdf_forms', 'owner_password')) { + db_add_field('fillpdf_forms', 'owner_password', $schema['fields']['owner_password']); + } + if (!db_field_exists('fillpdf_forms', 'user_password')) { + db_add_field('fillpdf_forms', 'user_password', $schema['fields']['user_password']); + } + if (!db_field_exists('fillpdf_forms', 'permissions')) { + db_add_field('fillpdf_forms', 'permissions', $schema['fields']['permissions']); + } +} + /** * Load a context object. * diff --git a/fillpdf.module b/fillpdf.module index f85ccd6..b6f69fc 100644 --- a/fillpdf.module +++ b/fillpdf.module @@ -1359,6 +1359,21 @@ function fillpdf_execute_merge($method, array $fields, $fillpdf, $mode = 'url', $pdftk_command[] = 'flatten'; } $pdftk_command[] = 'drop_xfa'; + // The value of this field is the same as the name of the PDFtk operation, + // which is why we don't do anything special to it. + if ($fillpdf->pdftk_encryption) { + $pdftk_command[] = $fillpdf->pdftk_encryption; + } + if ($fillpdf->permissions) { + $pdftk_command[] = 'allow ' . implode(' ', $fillpdf->permissions); + } + if ($fillpdf->owner_password) { + $pdftk_command[] = 'owner_pw ' . escapeshellarg($fillpdf->owner_password); + } + if ($fillpdf->user_password) { + $pdftk_command[] = 'user_pw ' . escapeshellarg($fillpdf->user_password); + } + ob_start(); passthru(implode(' ', $pdftk_command)); $data = ob_get_clean(); @@ -1792,6 +1807,13 @@ function fillpdf_load($fid, $reset = FALSE, $process_replacements = TRUE) { static $fillpdf = array(); if (!isset($fillpdf[$fid]) || $reset) { $fillpdf[$fid] = db_query("SELECT * FROM {fillpdf_forms} WHERE fid = :fid", array(':fid' => $fid))->fetch(); + + // Convert permissions back to a checkbox-compatible format. + $permissions = array(); + foreach (explode(',', $fillpdf[$fid]->permissions) as $permission) { + $permissions[$permission] = $permission; + } + $fillpdf[$fid]->permissions = $permissions; } if ($fillpdf[$fid]) { -- GitLab