mirror of
https://github.com/JakubMelka/PDF4QT.git
synced 2025-01-27 23:59:23 +01:00
Encryption settings dialog, authorization as owner
This commit is contained in:
parent
759d5c7793
commit
936fe2fbe7
@ -449,11 +449,6 @@ public:
|
||||
/// header.
|
||||
QByteArray getVersion() const;
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
friend class PDFDocumentBuilder;
|
||||
friend class PDFOptimizer;
|
||||
|
||||
explicit PDFDocument(PDFObjectStorage&& storage, PDFVersion version) :
|
||||
m_pdfObjectStorage(std::move(storage))
|
||||
{
|
||||
@ -462,6 +457,11 @@ private:
|
||||
m_info.version = version;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class PDFDocumentReader;
|
||||
friend class PDFDocumentBuilder;
|
||||
friend class PDFOptimizer;
|
||||
|
||||
/// Initialize data based on object in the storage.
|
||||
/// Can throw exception if error is detected.
|
||||
void init();
|
||||
|
@ -508,6 +508,11 @@ PDFSecurityHandlerPointer PDFSecurityHandler::createSecurityHandler(const PDFObj
|
||||
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)
|
||||
{
|
||||
QByteArray password;
|
||||
@ -664,7 +669,7 @@ PDFSecurityHandler::AuthorizationResult PDFStandardSecurityHandler::authenticate
|
||||
return AuthorizationResult::Failed;
|
||||
}
|
||||
|
||||
password = adjustPassword(getPasswordCallback(&passwordObtained));
|
||||
password = adjustPassword(getPasswordCallback(&passwordObtained), m_R);
|
||||
}
|
||||
|
||||
return AuthorizationResult::Cancelled;
|
||||
@ -1375,11 +1380,11 @@ PDFStandardSecurityHandler::UserOwnerData_r6 PDFStandardSecurityHandler::parsePa
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password)
|
||||
QByteArray PDFStandardSecurityHandler::adjustPassword(const QString& password, int revision)
|
||||
{
|
||||
QByteArray result;
|
||||
|
||||
switch (m_R)
|
||||
switch (revision)
|
||||
{
|
||||
case 2:
|
||||
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
|
||||
|
@ -109,6 +109,9 @@ public:
|
||||
/// Retrieve encryption mode (none/standard encryption/custom)
|
||||
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,
|
||||
/// 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.
|
||||
@ -214,6 +217,7 @@ class PDFNoneSecurityHandler : public PDFSecurityHandler
|
||||
{
|
||||
public:
|
||||
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 QByteArray decrypt(const QByteArray& data, PDFObjectReference, EncryptionScope) 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:
|
||||
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 QByteArray decrypt(const QByteArray& data, PDFObjectReference reference, EncryptionScope encryptionScope) const override;
|
||||
virtual QByteArray decryptByFilter(const QByteArray& data, const QByteArray& filterName, PDFObjectReference reference) const override;
|
||||
@ -249,6 +254,9 @@ public:
|
||||
QByteArray fileEncryptionKey;
|
||||
};
|
||||
|
||||
/// Adjusts the password according to the PDF specification
|
||||
static QByteArray adjustPassword(const QString& password, int revision);
|
||||
|
||||
private:
|
||||
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)
|
||||
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.
|
||||
/// \param data Data to be decrypted
|
||||
@ -356,6 +362,57 @@ private:
|
||||
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
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user