diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/SignaturePlugin.pro b/Pdf4QtViewerPlugins/SignaturePlugin/SignaturePlugin.pro index 9f4e2c9..c08e5d6 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/SignaturePlugin.pro +++ b/Pdf4QtViewerPlugins/SignaturePlugin/SignaturePlugin.pro @@ -43,13 +43,15 @@ SOURCES += \ certificatemanager.cpp \ certificatemanagerdialog.cpp \ createcertificatedialog.cpp \ - signatureplugin.cpp + signatureplugin.cpp \ + signdialog.cpp HEADERS += \ certificatemanager.h \ certificatemanagerdialog.h \ createcertificatedialog.h \ - signatureplugin.h + signatureplugin.h \ + signdialog.h CONFIG += force_debug_info @@ -61,5 +63,6 @@ RESOURCES += \ FORMS += \ certificatemanagerdialog.ui \ - createcertificatedialog.ui + createcertificatedialog.ui \ + signdialog.ui diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.cpp index f18f9ed..6854c3a 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.cpp +++ b/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.cpp @@ -132,6 +132,12 @@ void CertificateManager::createCertificate(const NewCertificateInfo& info) } } +QFileInfoList CertificateManager::getCertificates() +{ + QDir directory(getCertificateDirectory()); + return directory.entryInfoList(QStringList() << "*.pfx", QDir::Files | QDir::NoDotAndDotDot | QDir::Readable, QDir::Name); +} + QString CertificateManager::getCertificateDirectory() { QDir directory(QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).front() + "/certificates/"); @@ -156,4 +162,32 @@ QString CertificateManager::generateCertificateFileName() return QString(); } +bool CertificateManager::isCertificateValid(QString fileName, QString password) +{ + QFile file(fileName); + if (file.open(QFile::ReadOnly)) + { + QByteArray data = file.readAll(); + file.close(); + + openssl_ptr pksBuffer(BIO_new(BIO_s_mem()), &BIO_free_all); + BIO_write(pksBuffer.get(), data.constData(), data.length()); + + openssl_ptr pkcs12(d2i_PKCS12_bio(pksBuffer.get(), nullptr), &PKCS12_free); + if (pkcs12) + { + const char* passwordPointer = nullptr; + QByteArray passwordByteArray = password.isEmpty() ? QByteArray() : password.toUtf8(); + if (!passwordByteArray.isEmpty()) + { + passwordPointer = passwordByteArray.constData(); + } + + return PKCS12_parse(pkcs12.get(), passwordPointer, nullptr, nullptr, nullptr) == 1; + } + } + + return false; +} + } // namespace pdfplugin diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.h b/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.h index 47b8a92..7a52f4e 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.h +++ b/Pdf4QtViewerPlugins/SignaturePlugin/certificatemanager.h @@ -19,6 +19,7 @@ #define CERTIFICATEMANAGER_H #include +#include namespace pdfplugin { @@ -46,8 +47,10 @@ public: void createCertificate(const NewCertificateInfo& info); + static QFileInfoList getCertificates(); static QString getCertificateDirectory(); static QString generateCertificateFileName(); + static bool isCertificateValid(QString fileName, QString password); }; } // namespace pdfplugin diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp index d23beb2..6b9ae9c 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.cpp @@ -22,6 +22,7 @@ #include "pdfpagecontenteditorstylesettings.h" #include "pdfdocumentbuilder.h" #include "certificatemanagerdialog.h" +#include "signdialog.h" #include #include @@ -156,6 +157,7 @@ void SignaturePlugin::setWidget(pdf::PDFWidget* widget) connect(clearAction, &QAction::triggered, &m_scene, &pdf::PDFPageContentScene::clear); connect(activateAction, &QAction::triggered, this, &SignaturePlugin::setActive); connect(signElectronicallyAction, &QAction::triggered, this, &SignaturePlugin::onSignElectronically); + connect(signDigitallyAction, &QAction::triggered, this, &SignaturePlugin::onSignDigitally); connect(certificatesAction, &QAction::triggered, this, &SignaturePlugin::onOpenCertificatesManager); updateActions(); @@ -305,6 +307,28 @@ void SignaturePlugin::onSignElectronically() } } +void SignaturePlugin::onSignDigitally() +{ + // Jakub Melka: do we have certificates? If not, + // open certificate dialog, so the user can create + // a new one. + if (CertificateManager::getCertificates().isEmpty()) + { + onOpenCertificatesManager(); + + if (CertificateManager::getCertificates().isEmpty()) + { + return; + } + } + + SignDialog dialog(m_dataExchangeInterface->getMainWindow(), m_scene.isEmpty()); + if (dialog.exec() == SignDialog::Accepted) + { + + } +} + void SignaturePlugin::onOpenCertificatesManager() { CertificateManagerDialog dialog(m_dataExchangeInterface->getMainWindow()); @@ -422,7 +446,7 @@ void SignaturePlugin::updateActions() QAction* signElectronicallyAction = m_actions[SignElectronically]; signElectronicallyAction->setEnabled(isSceneNonempty); QAction* signDigitallyAction = m_actions[SignDigitally]; - signDigitallyAction->setEnabled(isSceneNonempty); + signDigitallyAction->setEnabled(m_document); } void SignaturePlugin::updateGraphics() diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h index 8e69b2a..db34c8a 100644 --- a/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signatureplugin.h @@ -54,6 +54,7 @@ private: void onToolActivityChanged(); void onSceneEditElement(const std::set& elements); void onSignElectronically(); + void onSignDigitally(); void onOpenCertificatesManager(); void onPenChanged(const QPen& pen); diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp new file mode 100644 index 0000000..eebadd4 --- /dev/null +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.cpp @@ -0,0 +1,90 @@ +// Copyright (C) 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 "signdialog.h" +#include "ui_signdialog.h" + +#include "certificatemanager.h" + +#include + +#include + +namespace pdfplugin +{ + +SignDialog::SignDialog(QWidget* parent, bool isSceneEmpty) : + QDialog(parent), + ui(new Ui::SignDialog) +{ + ui->setupUi(this); + + if (!isSceneEmpty) + { + ui->methodCombo->addItem(tr("Sign digitally"), SignDigitally); + } + + ui->methodCombo->addItem(tr("Sign digitally (invisible signature)"), SignDigitallyInvisible); + ui->methodCombo->setCurrentIndex(0); + + QFileInfoList certificates = CertificateManager::getCertificates(); + for (const QFileInfo& certificateFileInfo : certificates) + { + ui->certificateCombo->addItem(certificateFileInfo.fileName(), certificateFileInfo.absoluteFilePath()); + } +} + +SignDialog::~SignDialog() +{ + delete ui; +} + +SignDialog::SignMethod SignDialog::getSignMethod() const +{ + return static_cast(ui->methodCombo->currentData().toInt()); +} + +QString SignDialog::getCertificatePath() const +{ + return ui->certificateCombo->currentData().toString(); +} + +void SignDialog::accept() +{ + // Check certificate + if (!QFile::exists(getCertificatePath())) + { + QMessageBox::critical(this, tr("Error"), tr("Certificate does not exist.")); + ui->certificateCombo->setFocus(); + return; + } + + // Check we can access the certificate + if (!CertificateManager::isCertificateValid(getCertificatePath(), ui->certificatePasswordEdit->text())) + { + QMessageBox::critical(this, tr("Error"), tr("Password to open certificate is invalid.")); + ui->certificatePasswordEdit->setFocus(); + return; + } + + QDialog::accept(); +} + +} // namespace pdfplugin + + + diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h new file mode 100644 index 0000000..aa727da --- /dev/null +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.h @@ -0,0 +1,56 @@ +// Copyright (C) 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 . + +#ifndef SIGNDIALOG_H +#define SIGNDIALOG_H + +#include + +namespace Ui +{ +class SignDialog; +} + +namespace pdfplugin +{ + +class SignDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SignDialog(QWidget* parent, bool isSceneEmpty); + virtual ~SignDialog() override; + + virtual void accept() override; + + enum SignMethod + { + SignDigitally, + SignDigitallyInvisible + }; + + SignMethod getSignMethod() const; + QString getCertificatePath() const; + +private: + Ui::SignDialog* ui; +}; + +} // namespace pdfplugin + +#endif // SIGNDIALOG_H diff --git a/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.ui b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.ui new file mode 100644 index 0000000..d8c4466 --- /dev/null +++ b/Pdf4QtViewerPlugins/SignaturePlugin/signdialog.ui @@ -0,0 +1,160 @@ + + + SignDialog + + + + 0 + 0 + 501 + 332 + + + + Dialog + + + + + + Sign Method + + + + + + Method + + + + + + + + + + Certificate + + + + + + + + + + Password + + + + + + + QLineEdit::Password + + + true + + + + + + + + + + Parameters + + + + + + Reason + + + + + + + true + + + + + + + Contact Info + + + + + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SignDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SignDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +