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:
@ -449,11 +449,6 @@ public:
|
|||||||
/// header.
|
/// header.
|
||||||
QByteArray getVersion() const;
|
QByteArray getVersion() const;
|
||||||
|
|
||||||
private:
|
|
||||||
friend class PDFDocumentReader;
|
|
||||||
friend class PDFDocumentBuilder;
|
|
||||||
friend class PDFOptimizer;
|
|
||||||
|
|
||||||
explicit PDFDocument(PDFObjectStorage&& storage, PDFVersion version) :
|
explicit PDFDocument(PDFObjectStorage&& storage, PDFVersion version) :
|
||||||
m_pdfObjectStorage(std::move(storage))
|
m_pdfObjectStorage(std::move(storage))
|
||||||
{
|
{
|
||||||
@ -462,6 +457,11 @@ private:
|
|||||||
m_info.version = version;
|
m_info.version = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class PDFDocumentReader;
|
||||||
|
friend class PDFDocumentBuilder;
|
||||||
|
friend class PDFOptimizer;
|
||||||
|
|
||||||
/// Initialize data based on object in the storage.
|
/// Initialize data based on object in the storage.
|
||||||
/// Can throw exception if error is detected.
|
/// Can throw exception if error is detected.
|
||||||
void init();
|
void init();
|
||||||
|
@ -508,6 +508,11 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
|||||||
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
return PDFSecurityHandlerPointer(new PDFStandardSecurityHandler(qMove(handler)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFSecurityHandler* PDFStandardSecurityHandler::clone() const
|
||||||
|
{
|
||||||
|
return new PDFStandardSecurityHandler(*this);
|
||||||
|
}
|
||||||
|
|
||||||
PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly)
|
PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly)
|
||||||
{
|
{
|
||||||
QByteArray password;
|
QByteArray password;
|
||||||
@ -664,7 +669,7 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate
|
|||||||
return AuthorizationResult::Failed;
|
return AuthorizationResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
password = adjustPassword(getPasswordCallback(&passwordObtained));
|
password = adjustPassword(getPasswordCallback(&passwordObtained), m_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AuthorizationResult::Cancelled;
|
return AuthorizationResult::Cancelled;
|
||||||
@ -1375,11 +1380,11 @@ PDFStandardSecurityHandler::UserOwnerData_r6 PDFStandardSecurityHandler::parsePa
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password)
|
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password, int revision)
|
||||||
{
|
{
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
|
|
||||||
switch (m_R)
|
switch (revision)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
@ -1486,4 +1491,84 @@ bool PDFStandardSecurityHandler::isUnicodeMappedToNothing(ushort unicode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PDFSecurityHandlerPointer PDFSecurityHandlerFactory::createSecurityHandler(const PDFSecurityHandlerFactory::SecuritySettings& settings)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFSecurityHandlerFactory::getPasswordOptimalEntropy()
|
||||||
|
{
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFSecurityHandlerFactory::getPasswordEntropy(const QString& password, Algorithm algorithm)
|
||||||
|
{
|
||||||
|
if (algorithm == None)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray adjustedPassword = PDFStandardSecurityHandler::adjustPassword(password, getRevisionFromAlgorithm(algorithm));
|
||||||
|
|
||||||
|
if (adjustedPassword.isEmpty())
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int length = adjustedPassword.length();
|
||||||
|
std::sort(adjustedPassword.begin(), adjustedPassword.end());
|
||||||
|
|
||||||
|
int charCount = 0;
|
||||||
|
char lastChar = adjustedPassword.front();
|
||||||
|
PDFReal entropy = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
const char currentChar = adjustedPassword[i];
|
||||||
|
|
||||||
|
if (currentChar == lastChar)
|
||||||
|
{
|
||||||
|
++charCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const PDFReal probability = PDFReal(charCount) / PDFReal(length);
|
||||||
|
entropy += -probability * std::log2(probability);
|
||||||
|
|
||||||
|
charCount = 1;
|
||||||
|
lastChar = currentChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jakub Melka: last character
|
||||||
|
const PDFReal probability = PDFReal(charCount) / PDFReal(length);
|
||||||
|
entropy += -probability * std::log2(probability);
|
||||||
|
|
||||||
|
return entropy * length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PDFSecurityHandlerFactory::getRevisionFromAlgorithm(Algorithm algorithm)
|
||||||
|
{
|
||||||
|
switch (algorithm)
|
||||||
|
{
|
||||||
|
case None:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case RC4:
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
case AES_128:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case AES_256:
|
||||||
|
return 6;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
@ -109,6 +109,9 @@ public:
|
|||||||
/// Retrieve encryption mode (none/standard encryption/custom)
|
/// Retrieve encryption mode (none/standard encryption/custom)
|
||||||
virtual EncryptionMode getMode() const = 0;
|
virtual EncryptionMode getMode() const = 0;
|
||||||
|
|
||||||
|
/// Creates a clone of this object
|
||||||
|
virtual PDFSecurityHandler* clone() const = 0;
|
||||||
|
|
||||||
/// Performs authentication of the document content access. First, algorithm should check,
|
/// Performs authentication of the document content access. First, algorithm should check,
|
||||||
/// if empty password allows document access (so, for example, only owner password is provided).
|
/// if empty password allows document access (so, for example, only owner password is provided).
|
||||||
/// If this fails, function \p getPasswordCallback is called to retrieve user entered password.
|
/// If this fails, function \p getPasswordCallback is called to retrieve user entered password.
|
||||||
@ -214,6 +217,7 @@ class PDFNoneSecurityHandler : public PDFSecurityHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual EncryptionMode getMode() const override { return EncryptionMode::None; }
|
virtual EncryptionMode getMode() const override { return EncryptionMode::None; }
|
||||||
|
virtual PDFSecurityHandler* clone() const override { return new PDFNoneSecurityHandler(); }
|
||||||
virtual AuthorizationResult authenticate(const std::function<QString(bool*)>&, bool) override { return AuthorizationResult::OwnerAuthorized; }
|
virtual AuthorizationResult authenticate(const std::function<QString(bool*)>&, bool) override { return AuthorizationResult::OwnerAuthorized; }
|
||||||
virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; }
|
virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) const override { return data; }
|
||||||
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; }
|
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray&, PDFObjectReference) const override { return data; }
|
||||||
@ -231,6 +235,7 @@ class PDFStandardSecurityHandler : public PDFSecurityHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual EncryptionMode getMode() const override { return EncryptionMode::Standard; }
|
virtual EncryptionMode getMode() const override { return EncryptionMode::Standard; }
|
||||||
|
virtual PDFSecurityHandler* clone() const override;
|
||||||
virtual AuthorizationResult authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly) override;
|
virtual AuthorizationResult authenticate(const std::function<QString(bool*)>& getPasswordCallback, bool authorizeOwnerOnly) override;
|
||||||
virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override;
|
virtual QByteArray decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override;
|
||||||
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override;
|
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override;
|
||||||
@ -249,6 +254,9 @@ public:
|
|||||||
QByteArray fileEncryptionKey;
|
QByteArray fileEncryptionKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Adjusts the password according to the PDF specification
|
||||||
|
static QByteArray adjustPassword(const QString& password, int revision);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
friend PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObject& encryptionDictionaryObject, const QByteArray& id);
|
||||||
|
|
||||||
@ -288,8 +296,6 @@ private:
|
|||||||
/// Parses parts of the user/owner data (U/O values of the encryption dictionary)
|
/// Parses parts of the user/owner data (U/O values of the encryption dictionary)
|
||||||
UserOwnerData_r6 parseParts(const QByteArray& data) const;
|
UserOwnerData_r6 parseParts(const QByteArray& data) const;
|
||||||
|
|
||||||
/// Adjusts the password according to the PDF specification
|
|
||||||
QByteArray adjustPassword(const QString& password);
|
|
||||||
|
|
||||||
/// Decrypts data using specified filter. This function can be called only, if authorization was successfull.
|
/// Decrypts data using specified filter. This function can be called only, if authorization was successfull.
|
||||||
/// \param data Data to be decrypted
|
/// \param data Data to be decrypted
|
||||||
@ -356,6 +362,57 @@ private:
|
|||||||
AuthorizationData m_authorizationData;
|
AuthorizationData m_authorizationData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Factory, which creates security handler based on settings.
|
||||||
|
class Pdf4QtLIBSHARED_EXPORT PDFSecurityHandlerFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Algorithm
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
RC4,
|
||||||
|
AES_128,
|
||||||
|
AES_256
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EncryptContents
|
||||||
|
{
|
||||||
|
All,
|
||||||
|
AllExceptMetadata,
|
||||||
|
EmbeddedFiles
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SecuritySettings
|
||||||
|
{
|
||||||
|
Algorithm algorithm = None;
|
||||||
|
EncryptContents encryptContents = All;
|
||||||
|
QString userPassword;
|
||||||
|
QString ownerPassword;
|
||||||
|
uint32_t permissions = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Creates security handler based on given settings. If security handler cannot
|
||||||
|
/// be created, then nullptr is returned.
|
||||||
|
/// \param settings Security handler settings
|
||||||
|
static PDFSecurityHandlerPointer createSecurityHandler(const SecuritySettings& settings);
|
||||||
|
|
||||||
|
/// Returns optimal number of bits (entropy) for strong password
|
||||||
|
static int getPasswordOptimalEntropy();
|
||||||
|
|
||||||
|
/// Calculates password entropy (number of bits), can be used
|
||||||
|
/// for ranking the password security. Encryption algorithm must be also
|
||||||
|
/// considered, because password is adjusted according to the specification
|
||||||
|
/// before it's entropy is being computed.
|
||||||
|
/// \param password Password to be scored
|
||||||
|
/// \param algorithm Encryption algorithm
|
||||||
|
static int getPasswordEntropy(const QString& password, Algorithm algorithm);
|
||||||
|
|
||||||
|
/// Returns revision number of standard security handler for a given
|
||||||
|
/// algorithm. If algorithm is invalid or None, zero is returned.
|
||||||
|
/// \param algorithm Algorithm
|
||||||
|
static int getRevisionFromAlgorithm(Algorithm algorithm);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace pdf
|
} // namespace pdf
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,18 +18,58 @@
|
|||||||
#include "pdfencryptionsettingsdialog.h"
|
#include "pdfencryptionsettingsdialog.h"
|
||||||
#include "ui_pdfencryptionsettingsdialog.h"
|
#include "ui_pdfencryptionsettingsdialog.h"
|
||||||
|
|
||||||
|
#include "pdfutils.h"
|
||||||
|
#include "pdfsecurityhandler.h"
|
||||||
|
|
||||||
namespace pdfviewer
|
namespace pdfviewer
|
||||||
{
|
{
|
||||||
|
|
||||||
PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QWidget* parent) :
|
PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QWidget* parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
ui(new Ui::PDFEncryptionSettingsDialog)
|
ui(new Ui::PDFEncryptionSettingsDialog),
|
||||||
|
m_isUpdatingUi(false)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
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->algorithmHintWidget->setFixedSize(ui->algorithmHintWidget->minimumSizeHint());
|
||||||
ui->userPasswordStrengthHintWidget->setFixedSize(ui->userPasswordStrengthHintWidget->minimumSizeHint());
|
ui->userPasswordStrengthHintWidget->setFixedSize(ui->userPasswordStrengthHintWidget->minimumSizeHint());
|
||||||
ui->ownerPasswordStrengthHintWidget->setFixedSize(ui->ownerPasswordStrengthHintWidget->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()
|
PDFEncryptionSettingsDialog::~PDFEncryptionSettingsDialog()
|
||||||
@ -37,4 +77,78 @@ PDFEncryptionSettingsDialog::~PDFEncryptionSettingsDialog()
|
|||||||
delete ui;
|
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
|
} // namespace pdfviewer
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#define PDFENCRYPTIONSETTINGSDIALOG_H
|
#define PDFENCRYPTIONSETTINGSDIALOG_H
|
||||||
|
|
||||||
#include "pdfviewerglobal.h"
|
#include "pdfviewerglobal.h"
|
||||||
|
#include "pdfsecurityhandler.h"
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
@ -27,6 +28,8 @@ namespace Ui
|
|||||||
class PDFEncryptionSettingsDialog;
|
class PDFEncryptionSettingsDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QCheckBox;
|
||||||
|
|
||||||
namespace pdfviewer
|
namespace pdfviewer
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -40,6 +43,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::PDFEncryptionSettingsDialog* ui;
|
Ui::PDFEncryptionSettingsDialog* ui;
|
||||||
|
|
||||||
|
void updateUi();
|
||||||
|
void updatePasswordScore();
|
||||||
|
|
||||||
|
bool m_isUpdatingUi;
|
||||||
|
std::map<QCheckBox*, pdf::PDFSecurityHandler::Permission> m_checkBoxToPermission;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pdfviewer
|
} // namespace pdfviewer
|
||||||
|
@ -13,15 +13,15 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Encryption Settings</string>
|
<string>Encryption Settings</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<layout class="QVBoxLayout" name="dialogLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="encryptionMethodGroupBox">
|
<widget class="QGroupBox" name="encryptionMethodGroupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Encryption Method</string>
|
<string>Encryption Method</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="methodGroupBoxLayout">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="algotithmComboBox"/>
|
<widget class="QComboBox" name="algorithmComboBox"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="encryptionAlgorithm">
|
<widget class="QLabel" name="encryptionAlgorithm">
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Passwords</string>
|
<string>Passwords</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="passwordsGroupBoxLayout">
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="ownerPasswordEnableCheckBox">
|
<widget class="QCheckBox" name="ownerPasswordEnableCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -100,12 +100,15 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Encrypt Contents</string>
|
<string>Encrypt Contents</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="encryptGroupBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="encryptAllRadioButton">
|
<widget class="QRadioButton" name="encryptAllRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Encrypt all document contents, including document metadata</string>
|
<string>Encrypt all document contents, including document metadata</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
@ -130,7 +133,7 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Permissions</string>
|
<string>Permissions</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="permissionsGroupBoxLayout">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="permPrintLowResolutionCheckBox">
|
<widget class="QCheckBox" name="permPrintLowResolutionCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -139,7 +142,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_3">
|
<widget class="QCheckBox" name="permFillInteractiveFormsCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Fill interactive forms</string>
|
<string>Fill interactive forms</string>
|
||||||
</property>
|
</property>
|
||||||
@ -153,7 +156,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_4">
|
<widget class="QCheckBox" name="permAccessibilityCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Accessibility</string>
|
<string>Accessibility</string>
|
||||||
</property>
|
</property>
|
||||||
@ -167,7 +170,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_5">
|
<widget class="QCheckBox" name="permAssembleCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Assemble document (insert, rotate, delete pages...)</string>
|
<string>Assemble document (insert, rotate, delete pages...)</string>
|
||||||
</property>
|
</property>
|
||||||
@ -181,7 +184,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_6">
|
<widget class="QCheckBox" name="permCopyContentCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Copy/extract document content</string>
|
<string>Copy/extract document content</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -67,6 +67,7 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
|||||||
const QSize markSize = getMarkSize();
|
const QSize markSize = getMarkSize();
|
||||||
const int markSpacing = getMarkSpacing();
|
const int markSpacing = getMarkSpacing();
|
||||||
const int xAdvance = markSize.width() + markSpacing;
|
const int xAdvance = markSize.width() + markSpacing;
|
||||||
|
const bool isEnabled = this->isEnabled();
|
||||||
|
|
||||||
QRect rect = this->rect();
|
QRect rect = this->rect();
|
||||||
painter.fillRect(rect, Qt::lightGray);
|
painter.fillRect(rect, Qt::lightGray);
|
||||||
@ -78,11 +79,20 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
|||||||
{
|
{
|
||||||
--currentLevel;
|
--currentLevel;
|
||||||
}
|
}
|
||||||
|
if (!isEnabled)
|
||||||
|
{
|
||||||
|
currentLevel = -1;
|
||||||
|
}
|
||||||
|
|
||||||
Q_ASSERT(currentLevel >= 0);
|
Q_ASSERT(currentLevel >= -1);
|
||||||
Q_ASSERT(currentLevel < m_levels.size());
|
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;
|
QColor invalidColor = Qt::darkGray;
|
||||||
|
|
||||||
QRect markRect(QPoint(0, (rect.height() - markSize.height()) / 2), markSize);
|
QRect markRect(QPoint(0, (rect.height() - markSize.height()) / 2), markSize);
|
||||||
@ -97,7 +107,10 @@ void PDFEncryptionStrengthHintWidget::paintEvent(QPaintEvent* event)
|
|||||||
}
|
}
|
||||||
painter.restore();
|
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()
|
void PDFEncryptionStrengthHintWidget::correctValue()
|
||||||
|
@ -112,12 +112,12 @@ void PDFOptimizeDocumentDialog::onOptimizationStarted()
|
|||||||
void PDFOptimizeDocumentDialog::onOptimizationProgress(QString progressText)
|
void PDFOptimizeDocumentDialog::onOptimizationProgress(QString progressText)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_optimizationInProgress);
|
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()
|
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_future.waitForFinished();
|
||||||
m_optimizationInProgress = false;
|
m_optimizationInProgress = false;
|
||||||
m_wasOptimized = true;
|
m_wasOptimized = true;
|
||||||
|
@ -1133,6 +1133,40 @@ void PDFProgramController::onActionOptimizeTriggered()
|
|||||||
|
|
||||||
void PDFProgramController::onActionEncryptionTriggered()
|
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);
|
PDFEncryptionSettingsDialog dialog(m_mainWindow);
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user