mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-06-05 21:59:17 +02:00
Encryption settings dialog, authorization as owner
This commit is contained in:
@@ -18,18 +18,58 @@
|
||||
#include "pdfencryptionsettingsdialog.h"
|
||||
#include "ui_pdfencryptionsettingsdialog.h"
|
||||
|
||||
#include "pdfutils.h"
|
||||
#include "pdfsecurityhandler.h"
|
||||
|
||||
namespace pdfviewer
|
||||
{
|
||||
|
||||
PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::PDFEncryptionSettingsDialog)
|
||||
ui(new Ui::PDFEncryptionSettingsDialog),
|
||||
m_isUpdatingUi(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->algorithmComboBox->addItem(tr("None"), int(pdf::PDFSecurityHandlerFactory::None));
|
||||
ui->algorithmComboBox->addItem(tr("RC4 | R3"), int(pdf::PDFSecurityHandlerFactory::RC4));
|
||||
ui->algorithmComboBox->addItem(tr("AES 128-bit | R4"), int(pdf::PDFSecurityHandlerFactory::AES_128));
|
||||
ui->algorithmComboBox->addItem(tr("AES 256-bit | R6"), int(pdf::PDFSecurityHandlerFactory::AES_256));
|
||||
|
||||
ui->algorithmComboBox->setCurrentIndex(0);
|
||||
|
||||
ui->algorithmHintWidget->setFixedSize(ui->algorithmHintWidget->minimumSizeHint());
|
||||
ui->userPasswordStrengthHintWidget->setFixedSize(ui->userPasswordStrengthHintWidget->minimumSizeHint());
|
||||
ui->ownerPasswordStrengthHintWidget->setFixedSize(ui->ownerPasswordStrengthHintWidget->minimumSizeHint());
|
||||
|
||||
ui->algorithmHintWidget->setMinValue(1);
|
||||
ui->algorithmHintWidget->setMaxValue(5);
|
||||
|
||||
const int passwordOptimalEntropy = pdf::PDFSecurityHandlerFactory::getPasswordOptimalEntropy();
|
||||
|
||||
ui->userPasswordStrengthHintWidget->setMinValue(0);
|
||||
ui->userPasswordStrengthHintWidget->setMaxValue(passwordOptimalEntropy);
|
||||
|
||||
ui->ownerPasswordStrengthHintWidget->setMinValue(0);
|
||||
ui->ownerPasswordStrengthHintWidget->setMaxValue(passwordOptimalEntropy);
|
||||
|
||||
connect(ui->algorithmComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &PDFEncryptionSettingsDialog::updateUi);
|
||||
connect(ui->userPasswordEnableCheckBox, &QCheckBox::clicked, this, &PDFEncryptionSettingsDialog::updateUi);
|
||||
connect(ui->ownerPasswordEnableCheckBox, &QCheckBox::clicked, this, &PDFEncryptionSettingsDialog::updateUi);
|
||||
connect(ui->userPasswordEdit, &QLineEdit::textChanged, this, &PDFEncryptionSettingsDialog::updatePasswordScore);
|
||||
connect(ui->ownerPasswordEdit, &QLineEdit::textChanged, this, &PDFEncryptionSettingsDialog::updatePasswordScore);
|
||||
|
||||
m_checkBoxToPermission[ui->permPrintLowResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintLowResolution;
|
||||
m_checkBoxToPermission[ui->permModifyDocumentContentsCheckBox] = pdf::PDFSecurityHandler::Permission::Modify;
|
||||
m_checkBoxToPermission[ui->permCopyContentCheckBox] = pdf::PDFSecurityHandler::Permission::CopyContent;
|
||||
m_checkBoxToPermission[ui->permInteractiveItemsCheckBox] = pdf::PDFSecurityHandler::Permission::ModifyInteractiveItems;
|
||||
m_checkBoxToPermission[ui->permFillInteractiveFormsCheckBox] = pdf::PDFSecurityHandler::Permission::ModifyFormFields;
|
||||
m_checkBoxToPermission[ui->permAccessibilityCheckBox] = pdf::PDFSecurityHandler::Permission::Accessibility;
|
||||
m_checkBoxToPermission[ui->permAssembleCheckBox] = pdf::PDFSecurityHandler::Permission::Assemble;
|
||||
m_checkBoxToPermission[ui->permPrintHighResolutionCheckBox] = pdf::PDFSecurityHandler::Permission::PrintHighResolution;
|
||||
|
||||
updateUi();
|
||||
updatePasswordScore();
|
||||
}
|
||||
|
||||
PDFEncryptionSettingsDialog::~PDFEncryptionSettingsDialog()
|
||||
@@ -37,4 +77,78 @@ PDFEncryptionSettingsDialog::~PDFEncryptionSettingsDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PDFEncryptionSettingsDialog::updateUi()
|
||||
{
|
||||
if (m_isUpdatingUi)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pdf::PDFTemporaryValueChange guard(&m_isUpdatingUi, true);
|
||||
|
||||
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
||||
const bool encrypted = algorithm != pdf::PDFSecurityHandlerFactory::None;
|
||||
|
||||
switch (algorithm)
|
||||
{
|
||||
case pdf::PDFSecurityHandlerFactory::None:
|
||||
ui->algorithmHintWidget->setCurrentValue(1);
|
||||
break;
|
||||
case pdf::PDFSecurityHandlerFactory::RC4:
|
||||
ui->algorithmHintWidget->setCurrentValue(2);
|
||||
break;
|
||||
case pdf::PDFSecurityHandlerFactory::AES_128:
|
||||
ui->algorithmHintWidget->setCurrentValue(4);
|
||||
break;
|
||||
case pdf::PDFSecurityHandlerFactory::AES_256:
|
||||
ui->algorithmHintWidget->setCurrentValue(5);
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
ui->userPasswordEnableCheckBox->setEnabled(encrypted);
|
||||
ui->ownerPasswordEnableCheckBox->setEnabled(false);
|
||||
|
||||
if (!encrypted)
|
||||
{
|
||||
ui->userPasswordEnableCheckBox->setChecked(false);
|
||||
ui->ownerPasswordEnableCheckBox->setChecked(false);
|
||||
|
||||
ui->userPasswordEdit->clear();
|
||||
ui->ownerPasswordEdit->clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->ownerPasswordEnableCheckBox->setChecked(true);
|
||||
}
|
||||
|
||||
ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
||||
ui->ownerPasswordEdit->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
||||
|
||||
ui->userPasswordStrengthHintWidget->setEnabled(ui->userPasswordEnableCheckBox->isChecked());
|
||||
ui->ownerPasswordStrengthHintWidget->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked());
|
||||
|
||||
ui->encryptAllRadioButton->setEnabled(encrypted);
|
||||
ui->encryptAllExceptMetadataRadioButton->setEnabled(encrypted);
|
||||
ui->encryptFileAttachmentsOnlyRadioButton->setEnabled(encrypted);
|
||||
|
||||
for (const auto& permissionItem : m_checkBoxToPermission)
|
||||
{
|
||||
permissionItem.first->setEnabled(encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFEncryptionSettingsDialog::updatePasswordScore()
|
||||
{
|
||||
const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast<const pdf::PDFSecurityHandlerFactory::Algorithm>(ui->algorithmComboBox->currentData().toInt());
|
||||
const int userPasswordScore = pdf::PDFSecurityHandlerFactory::getPasswordEntropy(ui->userPasswordEdit->text(), algorithm);
|
||||
const int ownerPasswordScore = pdf::PDFSecurityHandlerFactory::getPasswordEntropy(ui->ownerPasswordEdit->text(), algorithm);
|
||||
|
||||
ui->userPasswordStrengthHintWidget->setCurrentValue(userPasswordScore);
|
||||
ui->ownerPasswordStrengthHintWidget->setCurrentValue(ownerPasswordScore);
|
||||
}
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#define PDFENCRYPTIONSETTINGSDIALOG_H
|
||||
|
||||
#include "pdfviewerglobal.h"
|
||||
#include "pdfsecurityhandler.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
@@ -27,6 +28,8 @@ namespace Ui
|
||||
class PDFEncryptionSettingsDialog;
|
||||
}
|
||||
|
||||
class QCheckBox;
|
||||
|
||||
namespace pdfviewer
|
||||
{
|
||||
|
||||
@@ -40,6 +43,12 @@ public:
|
||||
|
||||
private:
|
||||
Ui::PDFEncryptionSettingsDialog* ui;
|
||||
|
||||
void updateUi();
|
||||
void updatePasswordScore();
|
||||
|
||||
bool m_isUpdatingUi;
|
||||
std::map<QCheckBox*, pdf::PDFSecurityHandler::Permission> m_checkBoxToPermission;
|
||||
};
|
||||
|
||||
} // namespace pdfviewer
|
||||
|
@@ -13,15 +13,15 @@
|
||||
<property name="windowTitle">
|
||||
<string>Encryption Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QVBoxLayout" name="dialogLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="encryptionMethodGroupBox">
|
||||
<property name="title">
|
||||
<string>Encryption Method</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<layout class="QGridLayout" name="methodGroupBoxLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="algotithmComboBox"/>
|
||||
<widget class="QComboBox" name="algorithmComboBox"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="encryptionAlgorithm">
|
||||
@@ -51,7 +51,7 @@
|
||||
<property name="title">
|
||||
<string>Passwords</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QGridLayout" name="passwordsGroupBoxLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="ownerPasswordEnableCheckBox">
|
||||
<property name="text">
|
||||
@@ -100,12 +100,15 @@
|
||||
<property name="title">
|
||||
<string>Encrypt Contents</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="encryptGroupBoxLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="encryptAllRadioButton">
|
||||
<property name="text">
|
||||
<string>Encrypt all document contents, including document metadata</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -130,7 +133,7 @@
|
||||
<property name="title">
|
||||
<string>Permissions</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<layout class="QGridLayout" name="permissionsGroupBoxLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="permPrintLowResolutionCheckBox">
|
||||
<property name="text">
|
||||
@@ -139,7 +142,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_3">
|
||||
<widget class="QCheckBox" name="permFillInteractiveFormsCheckBox">
|
||||
<property name="text">
|
||||
<string>Fill interactive forms</string>
|
||||
</property>
|
||||
@@ -153,7 +156,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_4">
|
||||
<widget class="QCheckBox" name="permAccessibilityCheckBox">
|
||||
<property name="text">
|
||||
<string>Accessibility</string>
|
||||
</property>
|
||||
@@ -167,7 +170,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_5">
|
||||
<widget class="QCheckBox" name="permAssembleCheckBox">
|
||||
<property name="text">
|
||||
<string>Assemble document (insert, rotate, delete pages...)</string>
|
||||
</property>
|
||||
@@ -181,7 +184,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="checkBox_6">
|
||||
<widget class="QCheckBox" name="permCopyContentCheckBox">
|
||||
<property name="text">
|
||||
<string>Copy/extract document content</string>
|
||||
</property>
|
||||
|
@@ -67,6 +67,7 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
||||
const QSize markSize = getMarkSize();
|
||||
const int markSpacing = getMarkSpacing();
|
||||
const int xAdvance = markSize.width() + markSpacing;
|
||||
const bool isEnabled = this->isEnabled();
|
||||
|
||||
QRect rect = this->rect();
|
||||
painter.fillRect(rect, Qt::lightGray);
|
||||
@@ -78,11 +79,20 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
--currentLevel;
|
||||
}
|
||||
if (!isEnabled)
|
||||
{
|
||||
currentLevel = -1;
|
||||
}
|
||||
|
||||
Q_ASSERT(currentLevel >= 0);
|
||||
Q_ASSERT(currentLevel < m_levels.size());
|
||||
Q_ASSERT(currentLevel >= -1);
|
||||
Q_ASSERT(currentLevel == -1 || currentLevel < m_levels.size());
|
||||
|
||||
QColor fillColor = Qt::darkGray;
|
||||
if (currentLevel >= 0)
|
||||
{
|
||||
fillColor = m_levels[currentLevel].color;
|
||||
}
|
||||
|
||||
QColor fillColor = m_levels[currentLevel].color;
|
||||
QColor invalidColor = Qt::darkGray;
|
||||
|
||||
QRect markRect(QPoint(0, (rect.height() - markSize.height()) / 2), markSize);
|
||||
@@ -97,7 +107,10 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
||||
}
|
||||
painter.restore();
|
||||
|
||||
painter.drawText(rect, Qt::TextSingleLine | Qt::TextDontClip | Qt::AlignLeft | Qt::AlignVCenter, m_levels[currentLevel].text);
|
||||
if (isEnabled)
|
||||
{
|
||||
painter.drawText(rect, Qt::TextSingleLine | Qt::TextDontClip | Qt::AlignLeft | Qt::AlignVCenter, m_levels[currentLevel].text);
|
||||
}
|
||||
}
|
||||
|
||||
void PDFEncryptionStrengthHintWidget::correctValue()
|
||||
|
@@ -112,12 +112,12 @@ void PDFOptimizeDocumentDialog::onOptimizationStarted()
|
||||
void PDFOptimizeDocumentDialog::onOptimizationProgress(QString progressText)
|
||||
{
|
||||
Q_ASSERT(m_optimizationInProgress);
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText()).arg(progressText));
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText(), progressText));
|
||||
}
|
||||
|
||||
void PDFOptimizeDocumentDialog::onOptimizationFinished()
|
||||
{
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText()).arg(tr("Optimization finished!")));
|
||||
ui->logTextEdit->setPlainText(QString("%1\n%2").arg(ui->logTextEdit->toPlainText(), tr("Optimization finished!")));
|
||||
m_future.waitForFinished();
|
||||
m_optimizationInProgress = false;
|
||||
m_wasOptimized = true;
|
||||
|
@@ -1133,6 +1133,40 @@ void PDFProgramController::onActionOptimizeTriggered()
|
||||
|
||||
void PDFProgramController::onActionEncryptionTriggered()
|
||||
{
|
||||
// Check that we have owner acces to the document
|
||||
const pdf::PDFSecurityHandler* securityHandler = m_pdfDocument->getStorage().getSecurityHandler();
|
||||
pdf::PDFSecurityHandler::AuthorizationResult authorizationResult = securityHandler->getAuthorizationResult();
|
||||
if (authorizationResult != pdf::PDFSecurityHandler::AuthorizationResult::OwnerAuthorized &&
|
||||
authorizationResult != pdf::PDFSecurityHandler::AuthorizationResult::NoAuthorizationRequired)
|
||||
{
|
||||
// Jakub Melka: we must authorize as owner, otherwise we can't continue,
|
||||
// because we don't have sufficient permissions.
|
||||
pdf::PDFSecurityHandlerPointer clonedSecurityHandler(securityHandler->clone());
|
||||
|
||||
auto queryPassword = [this](bool* ok)
|
||||
{
|
||||
QString result;
|
||||
*ok = false;
|
||||
onQueryPasswordRequest(&result, ok);
|
||||
return result;
|
||||
};
|
||||
|
||||
authorizationResult = clonedSecurityHandler->authenticate(queryPassword, true);
|
||||
|
||||
if (authorizationResult != pdf::PDFSecurityHandler::AuthorizationResult::OwnerAuthorized)
|
||||
{
|
||||
QMessageBox::critical(m_mainWindow, QApplication::applicationDisplayName(), tr("Permission to change document security is denied."));
|
||||
return;
|
||||
}
|
||||
|
||||
pdf::PDFObjectStorage storage = m_pdfDocument->getStorage();
|
||||
storage.setSecurityHandler(qMove(clonedSecurityHandler));
|
||||
|
||||
pdf::PDFDocumentPointer pointer(new pdf::PDFDocument(qMove(storage), m_pdfDocument->getInfo()->version));
|
||||
pdf::PDFModifiedDocument document(qMove(pointer), m_optionalContentActivity, pdf::PDFModifiedDocument::Reset);
|
||||
onDocumentModified(qMove(document));
|
||||
}
|
||||
|
||||
PDFEncryptionSettingsDialog dialog(m_mainWindow);
|
||||
dialog.exec();
|
||||
}
|
||||
|
Reference in New Issue
Block a user