// Copyright (C) 2021-2022 Jakub Melka // // This file is part of PDF4QT. // // PDF4QT is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // with the written consent of the copyright owner, any later version. // // PDF4QT is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with PDF4QT. If not, see . #include "pdfencryptionsettingsdialog.h" #include "ui_pdfencryptionsettingsdialog.h" #include "pdfencryptionstrengthhintwidget.h" #include "pdfutils.h" #include "pdfwidgetutils.h" #include "pdfsecurityhandler.h" #include "pdfcertificatemanager.h" #include "pdfdbgheap.h" #include namespace pdfviewer { PDFEncryptionSettingsDialog::PDFEncryptionSettingsDialog(QByteArray documentId, QWidget* parent) : QDialog(parent), ui(new Ui::PDFEncryptionSettingsDialog), m_isUpdatingUi(false), m_documentId(documentId), m_userPasswordStrengthHintWidget(new PDFEncryptionStrengthHintWidget(this)), m_ownerPasswordStrengthHintWidget(new PDFEncryptionStrengthHintWidget(this)), m_algorithmHintWidget(new PDFEncryptionStrengthHintWidget(this)) { ui->setupUi(this); ui->algorithmComboBox->addItem(tr("None"), int(pdf::PDFSecurityHandlerFactory::None)); ui->algorithmComboBox->addItem(tr("RC4 128-bit | R4"), 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->addItem(tr("Certificate Encryption"), int(pdf::PDFSecurityHandlerFactory::Certificate)); ui->algorithmComboBox->setCurrentIndex(0); m_algorithmHintWidget->setFixedSize(m_algorithmHintWidget->minimumSizeHint()); m_userPasswordStrengthHintWidget->setFixedSize(m_userPasswordStrengthHintWidget->minimumSizeHint()); m_ownerPasswordStrengthHintWidget->setFixedSize(m_userPasswordStrengthHintWidget->minimumSizeHint()); ui->passwordsGroupBoxLayout->addWidget(m_userPasswordStrengthHintWidget, 0, 2); ui->passwordsGroupBoxLayout->addWidget(m_ownerPasswordStrengthHintWidget, 1, 2); ui->methodGroupBoxLayout->addWidget(m_algorithmHintWidget, 0, 2); m_algorithmHintWidget->setMinValue(1); m_algorithmHintWidget->setMaxValue(5); const int passwordOptimalEntropy = pdf::PDFSecurityHandlerFactory::getPasswordOptimalEntropy(); m_userPasswordStrengthHintWidget->setMinValue(0); m_userPasswordStrengthHintWidget->setMaxValue(passwordOptimalEntropy); m_ownerPasswordStrengthHintWidget->setMinValue(0); m_ownerPasswordStrengthHintWidget->setMaxValue(passwordOptimalEntropy); connect(ui->algorithmComboBox, QOverload::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; updateCertificates(); updateUi(); updatePasswordScore(); pdf::PDFWidgetUtils::style(this); } PDFEncryptionSettingsDialog::~PDFEncryptionSettingsDialog() { delete ui; } void PDFEncryptionSettingsDialog::updateUi() { if (m_isUpdatingUi) { return; } pdf::PDFTemporaryValueChange guard(&m_isUpdatingUi, true); const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast(ui->algorithmComboBox->currentData().toInt()); const bool encrypted = algorithm != pdf::PDFSecurityHandlerFactory::None; const bool isEncryptedUsingCertificate = algorithm == pdf::PDFSecurityHandlerFactory::Certificate; switch (algorithm) { case pdf::PDFSecurityHandlerFactory::None: m_algorithmHintWidget->setCurrentValue(1); break; case pdf::PDFSecurityHandlerFactory::RC4: m_algorithmHintWidget->setCurrentValue(2); break; case pdf::PDFSecurityHandlerFactory::AES_128: m_algorithmHintWidget->setCurrentValue(4); break; case pdf::PDFSecurityHandlerFactory::AES_256: case pdf::PDFSecurityHandlerFactory::Certificate: m_algorithmHintWidget->setCurrentValue(5); break; default: Q_ASSERT(false); break; } ui->certificateComboBox->setEnabled(isEncryptedUsingCertificate); if (!isEncryptedUsingCertificate) { 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->certificateComboBox->setCurrentIndex(-1); } else { ui->userPasswordEnableCheckBox->setEnabled(false); ui->ownerPasswordEnableCheckBox->setEnabled(false); ui->userPasswordEnableCheckBox->setChecked(true); ui->ownerPasswordEnableCheckBox->setChecked(false); if (ui->certificateComboBox->currentIndex() == -1 && ui->certificateComboBox->count() > 0) { ui->certificateComboBox->setCurrentIndex(0); } } ui->userPasswordEdit->setEnabled(ui->userPasswordEnableCheckBox->isChecked()); ui->ownerPasswordEdit->setEnabled(ui->ownerPasswordEnableCheckBox->isChecked()); if (!ui->userPasswordEdit->isEnabled()) { ui->userPasswordEdit->clear(); } if (!ui->ownerPasswordEdit->isEnabled()) { ui->ownerPasswordEdit->clear(); } m_userPasswordStrengthHintWidget->setEnabled(ui->userPasswordEnableCheckBox->isChecked()); m_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::updateCertificates() { QFileInfoList certificates = pdf::PDFCertificateManager::getCertificates(); QVariant currentCertificate = ui->certificateComboBox->currentData(); ui->certificateComboBox->clear(); for (const QFileInfo& certificateItem : certificates) { ui->certificateComboBox->addItem(certificateItem.fileName(), certificateItem.absoluteFilePath()); } ui->certificateComboBox->setCurrentIndex(ui->certificateComboBox->findData(currentCertificate)); } void PDFEncryptionSettingsDialog::updatePasswordScore() { const pdf::PDFSecurityHandlerFactory::Algorithm algorithm = static_cast(ui->algorithmComboBox->currentData().toInt()); const int userPasswordScore = pdf::PDFSecurityHandlerFactory::getPasswordEntropy(ui->userPasswordEdit->text(), algorithm); const int ownerPasswordScore = pdf::PDFSecurityHandlerFactory::getPasswordEntropy(ui->ownerPasswordEdit->text(), algorithm); m_userPasswordStrengthHintWidget->setCurrentValue(userPasswordScore); m_ownerPasswordStrengthHintWidget->setCurrentValue(ownerPasswordScore); } void PDFEncryptionSettingsDialog::accept() { pdf::PDFSecurityHandlerFactory::SecuritySettings settings; pdf::PDFSecurityHandlerFactory::EncryptContents encryptContents = pdf::PDFSecurityHandlerFactory::All; if (ui->encryptAllExceptMetadataRadioButton->isChecked()) { encryptContents = pdf::PDFSecurityHandlerFactory::AllExceptMetadata; } else if (ui->encryptFileAttachmentsOnlyRadioButton->isChecked()) { encryptContents = pdf::PDFSecurityHandlerFactory::EmbeddedFiles; } settings.id = m_documentId; settings.algorithm = static_cast(ui->algorithmComboBox->currentData().toInt()); settings.encryptContents = encryptContents; settings.userPassword = ui->userPasswordEdit->text(); settings.ownerPassword = ui->ownerPasswordEdit->text(); settings.permissions = 0; settings.certificateFileName = ui->certificateComboBox->currentData().toString(); for (auto item : m_checkBoxToPermission) { if (item.first->isChecked()) { settings.permissions += uint32_t(item.second); } } QString errorMessage; if (!pdf::PDFSecurityHandlerFactory::validate(settings, &errorMessage)) { QMessageBox::critical(this, tr("Error"), errorMessage); return; } m_updatedSecurityHandler = pdf::PDFSecurityHandlerFactory::createSecurityHandler(settings); QDialog::accept(); } } // namespace pdfviewer