mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 14:14:10 +00:00
PDF: Allow signing unsigned signature fields
This commit is contained in:
parent
d59967d8e1
commit
a8e5f6e9f7
|
@ -47,6 +47,11 @@ if(Poppler_Qt5_FOUND)
|
|||
TEST_NAME "formattest"
|
||||
LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore
|
||||
)
|
||||
|
||||
ecm_add_test(signunsignedfieldtest
|
||||
TEST_NAME "signunsignedfieldtest"
|
||||
LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore
|
||||
)
|
||||
endif()
|
||||
|
||||
ecm_add_test(documenttest.cpp
|
||||
|
|
BIN
autotests/data/fake_okular_certstore/cert9.db
Normal file
BIN
autotests/data/fake_okular_certstore/cert9.db
Normal file
Binary file not shown.
BIN
autotests/data/fake_okular_certstore/key4.db
Normal file
BIN
autotests/data/fake_okular_certstore/key4.db
Normal file
Binary file not shown.
5
autotests/data/fake_okular_certstore/pkcs11.txt
Normal file
5
autotests/data/fake_okular_certstore/pkcs11.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
library=
|
||||
name=NSS Internal PKCS #11 Module
|
||||
parameters=configdir='testest' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription=''
|
||||
NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30})
|
||||
|
BIN
autotests/data/hello_with_dummy_signature.pdf
Normal file
BIN
autotests/data/hello_with_dummy_signature.pdf
Normal file
Binary file not shown.
123
autotests/signunsignedfieldtest.cpp
Normal file
123
autotests/signunsignedfieldtest.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2022 Albert Astals Cid <aacid@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLineEdit>
|
||||
#include <QMimeDatabase>
|
||||
#include <QPushButton>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTest>
|
||||
#include <QTimer>
|
||||
|
||||
#include "../core/document.h"
|
||||
#include "../core/form.h"
|
||||
#include "../core/page.h"
|
||||
#include "../settings_core.h"
|
||||
|
||||
class EnterPasswordDialogHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EnterPasswordDialogHelper()
|
||||
{
|
||||
QTimer::singleShot(0, this, &EnterPasswordDialogHelper::enterPassword);
|
||||
}
|
||||
|
||||
void enterPassword()
|
||||
{
|
||||
QWidget *dialog = qApp->activeModalWidget();
|
||||
if (!dialog) {
|
||||
QTimer::singleShot(0, this, &EnterPasswordDialogHelper::enterPassword);
|
||||
return;
|
||||
}
|
||||
QLineEdit *lineEdit = dialog->findChild<QLineEdit *>();
|
||||
lineEdit->setText(QStringLiteral("fakeokular"));
|
||||
|
||||
QDialogButtonBox *buttonBox = dialog->findChild<QDialogButtonBox *>();
|
||||
buttonBox->button(QDialogButtonBox::Ok)->click();
|
||||
}
|
||||
};
|
||||
|
||||
class SignUnsignedFieldTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
void testSignUnsignedField();
|
||||
|
||||
private:
|
||||
Okular::Document *m_document;
|
||||
};
|
||||
|
||||
void SignUnsignedFieldTest::initTestCase()
|
||||
{
|
||||
QStandardPaths::setTestModeEnabled(true);
|
||||
Okular::SettingsCore::instance(QStringLiteral("signunsignedfieldtest"));
|
||||
|
||||
KConfig cfg(QStringLiteral("okular-generator-popplerrc"));
|
||||
KConfigGroup g = cfg.group(QStringLiteral("Signatures"));
|
||||
g.writeEntry(QStringLiteral("UseDefaultCertDB"), false);
|
||||
g.writeEntry(QStringLiteral("DBCertificatePath"), "file://" KDESRCDIR "data/fake_okular_certstore");
|
||||
|
||||
m_document = new Okular::Document(nullptr);
|
||||
}
|
||||
|
||||
void SignUnsignedFieldTest::init()
|
||||
{
|
||||
const QString testFile = QStringLiteral(KDESRCDIR "data/hello_with_dummy_signature.pdf");
|
||||
QMimeDatabase db;
|
||||
const QMimeType mime = db.mimeTypeForFile(testFile);
|
||||
QCOMPARE(m_document->openDocument(testFile, QUrl(), mime), Okular::Document::OpenSuccess);
|
||||
}
|
||||
|
||||
void SignUnsignedFieldTest::cleanup()
|
||||
{
|
||||
m_document->closeDocument();
|
||||
}
|
||||
|
||||
void SignUnsignedFieldTest::testSignUnsignedField()
|
||||
{
|
||||
const QLinkedList<Okular::FormField *> forms = m_document->page(0)->formFields();
|
||||
QCOMPARE(forms.count(), 1);
|
||||
Okular::FormFieldSignature *ffs = dynamic_cast<Okular::FormFieldSignature *>(forms.first());
|
||||
|
||||
// This is a hacky way of doing ifdef HAVE_POPPLER_22_02
|
||||
if (m_document->metaData(QStringLiteral("CanSignDocumentWithPassword")).toString() == QLatin1String("yes")) {
|
||||
QCOMPARE(ffs->signatureType(), Okular::FormFieldSignature::UnsignedSignature);
|
||||
|
||||
const Okular::CertificateStore *certStore = m_document->certificateStore();
|
||||
bool userCancelled, nonDateValidCerts;
|
||||
{
|
||||
EnterPasswordDialogHelper helper;
|
||||
const QList<Okular::CertificateInfo *> &certs = certStore->signingCertificatesForNow(&userCancelled, &nonDateValidCerts);
|
||||
QCOMPARE(certs.count(), 1);
|
||||
}
|
||||
|
||||
Okular::NewSignatureData data;
|
||||
data.setCertNickname(QStringLiteral("fake-okular"));
|
||||
QTemporaryFile f;
|
||||
f.open();
|
||||
QVERIFY(ffs->sign(data, f.fileName()));
|
||||
|
||||
m_document->closeDocument();
|
||||
QMimeDatabase db;
|
||||
const QMimeType mime = db.mimeTypeForFile(f.fileName());
|
||||
QCOMPARE(m_document->openDocument(f.fileName(), QUrl(), mime), Okular::Document::OpenSuccess);
|
||||
|
||||
const QLinkedList<Okular::FormField *> newForms = m_document->page(0)->formFields();
|
||||
QCOMPARE(newForms.count(), 1);
|
||||
ffs = dynamic_cast<Okular::FormFieldSignature *>(newForms.first());
|
||||
QCOMPARE(ffs->signatureType(), Okular::FormFieldSignature::AdbePkcs7detached);
|
||||
QCOMPARE(ffs->signatureInfo().signerName(), "FakeOkular");
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(SignUnsignedFieldTest)
|
||||
#include "signunsignedfieldtest.moc"
|
16
core/form.h
16
core/form.h
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "annotations.h"
|
||||
#include "area.h"
|
||||
#include "document.h"
|
||||
#include "okularcore_export.h"
|
||||
#include "signatureutils.h"
|
||||
|
||||
|
@ -456,7 +457,13 @@ public:
|
|||
/**
|
||||
* The types of signature.
|
||||
*/
|
||||
enum SignatureType { AdbePkcs7sha1, AdbePkcs7detached, EtsiCAdESdetached, UnknownType };
|
||||
enum SignatureType {
|
||||
AdbePkcs7sha1,
|
||||
AdbePkcs7detached,
|
||||
EtsiCAdESdetached,
|
||||
UnknownType,
|
||||
UnsignedSignature ///< The signature field has not been signed yet. @since 22.04
|
||||
};
|
||||
|
||||
~FormFieldSignature() override;
|
||||
|
||||
|
@ -470,6 +477,13 @@ public:
|
|||
*/
|
||||
virtual const SignatureInfo &signatureInfo() const = 0;
|
||||
|
||||
/**
|
||||
Signs a field of UnsignedSignature type.
|
||||
|
||||
@since 22.04
|
||||
*/
|
||||
virtual bool sign(const NewSignatureData &data, const QString &newPath) const = 0;
|
||||
|
||||
protected:
|
||||
FormFieldSignature();
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ check_cxx_source_compiles("
|
|||
#include <poppler-form.h>
|
||||
int main()
|
||||
{
|
||||
auto us = Poppler::FormFieldSignature::UnsignedSignature;
|
||||
Poppler::PDFConverter::NewSignatureData pData;
|
||||
pData.setDocumentOwnerPassword(QByteArray());
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "core/action.h"
|
||||
|
||||
#include "generator_pdf.h"
|
||||
#include "pdfsettings.h"
|
||||
#include "pdfsignatureutils.h"
|
||||
|
||||
|
@ -453,6 +454,10 @@ PopplerFormFieldSignature::SignatureType PopplerFormFieldSignature::signatureTyp
|
|||
return Okular::FormFieldSignature::AdbePkcs7detached;
|
||||
case Poppler::FormFieldSignature::EtsiCAdESdetached:
|
||||
return Okular::FormFieldSignature::EtsiCAdESdetached;
|
||||
#ifdef HAVE_POPPLER_22_02
|
||||
case Poppler::FormFieldSignature::UnsignedSignature:
|
||||
return Okular::FormFieldSignature::UnsignedSignature;
|
||||
#endif
|
||||
default:
|
||||
return Okular::FormFieldSignature::UnknownType;
|
||||
}
|
||||
|
@ -462,3 +467,16 @@ const Okular::SignatureInfo &PopplerFormFieldSignature::signatureInfo() const
|
|||
{
|
||||
return *m_info;
|
||||
}
|
||||
|
||||
bool PopplerFormFieldSignature::sign(const Okular::NewSignatureData &oData, const QString &newPath) const
|
||||
{
|
||||
#ifdef HAVE_POPPLER_22_02
|
||||
Poppler::PDFConverter::NewSignatureData pData;
|
||||
PDFGenerator::okularToPoppler(oData, &pData);
|
||||
return m_field->sign(newPath, pData) == Poppler::FormFieldSignature::SigningSuccess;
|
||||
#else
|
||||
Q_UNUSED(oData)
|
||||
Q_UNUSED(newPath)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
// inherited from Okular::FormFieldSignature
|
||||
SignatureType signatureType() const override;
|
||||
const Okular::SignatureInfo &signatureInfo() const override;
|
||||
bool sign(const Okular::NewSignatureData &oData, const QString &newPath) const override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poppler::FormFieldSignature> m_field;
|
||||
|
|
|
@ -1312,6 +1312,28 @@ QByteArray PDFGenerator::requestFontData(const Okular::FontInfo &font)
|
|||
return pdfdoc->fontData(fi);
|
||||
}
|
||||
|
||||
#ifdef HAVE_POPPLER_SIGNING
|
||||
void PDFGenerator::okularToPoppler(const Okular::NewSignatureData &oData, Poppler::PDFConverter::NewSignatureData *pData)
|
||||
{
|
||||
pData->setCertNickname(oData.certNickname());
|
||||
pData->setPassword(oData.password());
|
||||
pData->setPage(oData.page());
|
||||
const QString datetime = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss t"));
|
||||
pData->setSignatureText(i18n("Signed by: %1\n\nDate: %2", oData.certSubjectCommonName(), datetime));
|
||||
#ifdef HAVE_POPPLER_FANCY_SIGNATURE
|
||||
pData->setSignatureLeftText(oData.certSubjectCommonName());
|
||||
#endif
|
||||
const Okular::NormalizedRect bRect = oData.boundingRectangle();
|
||||
pData->setBoundingRectangle({bRect.left, bRect.top, bRect.width(), bRect.height()});
|
||||
pData->setFontColor(Qt::black);
|
||||
pData->setBorderColor(Qt::black);
|
||||
#ifdef HAVE_POPPLER_22_02
|
||||
pData->setDocumentOwnerPassword(oData.documentPassword().toLatin1());
|
||||
pData->setDocumentUserPassword(oData.documentPassword().toLatin1());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DUMMY_QPRINTER_COPY
|
||||
Okular::Document::PrintError PDFGenerator::print(QPrinter &printer)
|
||||
{
|
||||
|
@ -1954,22 +1976,7 @@ bool PDFGenerator::sign(const Okular::NewSignatureData &oData, const QString &rF
|
|||
converter->setPDFOptions(converter->pdfOptions() | Poppler::PDFConverter::WithChanges);
|
||||
|
||||
Poppler::PDFConverter::NewSignatureData pData;
|
||||
pData.setCertNickname(oData.certNickname());
|
||||
pData.setPassword(oData.password());
|
||||
pData.setPage(oData.page());
|
||||
const QString datetime = QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss t"));
|
||||
pData.setSignatureText(i18n("Signed by: %1\n\nDate: %2", oData.certSubjectCommonName(), datetime));
|
||||
#ifdef HAVE_POPPLER_FANCY_SIGNATURE
|
||||
pData.setSignatureLeftText(oData.certSubjectCommonName());
|
||||
#endif
|
||||
const Okular::NormalizedRect bRect = oData.boundingRectangle();
|
||||
pData.setBoundingRectangle({bRect.left, bRect.top, bRect.width(), bRect.height()});
|
||||
pData.setFontColor(Qt::black);
|
||||
pData.setBorderColor(Qt::black);
|
||||
#ifdef HAVE_POPPLER_22_02
|
||||
pData.setDocumentOwnerPassword(oData.documentPassword().toLatin1());
|
||||
pData.setDocumentUserPassword(oData.documentPassword().toLatin1());
|
||||
#endif
|
||||
okularToPoppler(oData, &pData);
|
||||
if (!converter->sign(pData))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -108,6 +108,10 @@ public:
|
|||
|
||||
QByteArray requestFontData(const Okular::FontInfo &font) override;
|
||||
|
||||
#ifdef HAVE_POPPLER_SIGNING
|
||||
static void okularToPoppler(const Okular::NewSignatureData &oData, Poppler::PDFConverter::NewSignatureData *pData);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
SwapBackingFileResult swapBackingFile(QString const &newFileName, QVector<Okular::Page *> &newPagesVector) override;
|
||||
bool doCloseDocument() override;
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
*/
|
||||
|
||||
#include "formwidgets.h"
|
||||
#include "pageview.h"
|
||||
#include "pageviewutils.h"
|
||||
#include "revisionviewer.h"
|
||||
#include "signatureguiutils.h"
|
||||
#include "signaturepropertiesdialog.h"
|
||||
|
||||
#include <KLineEdit>
|
||||
|
@ -222,7 +224,7 @@ void FormWidgetsController::slotFormButtonsChangedByUndoRedo(int pageNumber, con
|
|||
emit changed(pageNumber);
|
||||
}
|
||||
|
||||
FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget *parent)
|
||||
FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, PageView *pageView)
|
||||
{
|
||||
FormWidgetIface *widget = nullptr;
|
||||
|
||||
|
@ -231,13 +233,13 @@ FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget
|
|||
Okular::FormFieldButton *ffb = static_cast<Okular::FormFieldButton *>(ff);
|
||||
switch (ffb->buttonType()) {
|
||||
case Okular::FormFieldButton::Push:
|
||||
widget = new PushButtonEdit(ffb, parent);
|
||||
widget = new PushButtonEdit(ffb, pageView);
|
||||
break;
|
||||
case Okular::FormFieldButton::CheckBox:
|
||||
widget = new CheckBoxEdit(ffb, parent);
|
||||
widget = new CheckBoxEdit(ffb, pageView);
|
||||
break;
|
||||
case Okular::FormFieldButton::Radio:
|
||||
widget = new RadioButtonEdit(ffb, parent);
|
||||
widget = new RadioButtonEdit(ffb, pageView);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
@ -247,13 +249,13 @@ FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget
|
|||
Okular::FormFieldText *fft = static_cast<Okular::FormFieldText *>(ff);
|
||||
switch (fft->textType()) {
|
||||
case Okular::FormFieldText::Multiline:
|
||||
widget = new TextAreaEdit(fft, parent);
|
||||
widget = new TextAreaEdit(fft, pageView);
|
||||
break;
|
||||
case Okular::FormFieldText::Normal:
|
||||
widget = new FormLineEdit(fft, parent);
|
||||
widget = new FormLineEdit(fft, pageView);
|
||||
break;
|
||||
case Okular::FormFieldText::FileSelect:
|
||||
widget = new FileEdit(fft, parent);
|
||||
widget = new FileEdit(fft, pageView);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -262,10 +264,10 @@ FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget
|
|||
Okular::FormFieldChoice *ffc = static_cast<Okular::FormFieldChoice *>(ff);
|
||||
switch (ffc->choiceType()) {
|
||||
case Okular::FormFieldChoice::ListBox:
|
||||
widget = new ListEdit(ffc, parent);
|
||||
widget = new ListEdit(ffc, pageView);
|
||||
break;
|
||||
case Okular::FormFieldChoice::ComboBox:
|
||||
widget = new ComboEdit(ffc, parent);
|
||||
widget = new ComboEdit(ffc, pageView);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -273,7 +275,7 @@ FormWidgetIface *FormWidgetFactory::createWidget(Okular::FormField *ff, QWidget
|
|||
case Okular::FormField::FormSignature: {
|
||||
Okular::FormFieldSignature *ffs = static_cast<Okular::FormFieldSignature *>(ff);
|
||||
if (ffs->isVisible() && ffs->signatureType() != Okular::FormFieldSignature::UnknownType)
|
||||
widget = new SignatureEdit(ffs, parent);
|
||||
widget = new SignatureEdit(ffs, pageView);
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
|
@ -363,8 +365,8 @@ void FormWidgetIface::slotRefresh(Okular::FormField *form)
|
|||
m_widget->setEnabled(!form->isReadOnly());
|
||||
}
|
||||
|
||||
PushButtonEdit::PushButtonEdit(Okular::FormFieldButton *button, QWidget *parent)
|
||||
: QPushButton(parent)
|
||||
PushButtonEdit::PushButtonEdit(Okular::FormFieldButton *button, PageView *pageView)
|
||||
: QPushButton(pageView->viewport())
|
||||
, FormWidgetIface(this, button)
|
||||
{
|
||||
setText(button->caption());
|
||||
|
@ -377,8 +379,8 @@ PushButtonEdit::PushButtonEdit(Okular::FormFieldButton *button, QWidget *parent)
|
|||
setCursor(Qt::ArrowCursor);
|
||||
}
|
||||
|
||||
CheckBoxEdit::CheckBoxEdit(Okular::FormFieldButton *button, QWidget *parent)
|
||||
: QCheckBox(parent)
|
||||
CheckBoxEdit::CheckBoxEdit(Okular::FormFieldButton *button, PageView *pageView)
|
||||
: QCheckBox(pageView->viewport())
|
||||
, FormWidgetIface(this, button)
|
||||
{
|
||||
setText(button->caption());
|
||||
|
@ -418,8 +420,8 @@ void CheckBoxEdit::slotRefresh(Okular::FormField *form)
|
|||
}
|
||||
}
|
||||
|
||||
RadioButtonEdit::RadioButtonEdit(Okular::FormFieldButton *button, QWidget *parent)
|
||||
: QRadioButton(parent)
|
||||
RadioButtonEdit::RadioButtonEdit(Okular::FormFieldButton *button, PageView *pageView)
|
||||
: QRadioButton(pageView->viewport())
|
||||
, FormWidgetIface(this, button)
|
||||
{
|
||||
setText(button->caption());
|
||||
|
@ -436,8 +438,8 @@ void RadioButtonEdit::setFormWidgetsController(FormWidgetsController *controller
|
|||
setChecked(form->state());
|
||||
}
|
||||
|
||||
FormLineEdit::FormLineEdit(Okular::FormFieldText *text, QWidget *parent)
|
||||
: QLineEdit(parent)
|
||||
FormLineEdit::FormLineEdit(Okular::FormFieldText *text, PageView *pageView)
|
||||
: QLineEdit(pageView->viewport())
|
||||
, FormWidgetIface(this, text)
|
||||
{
|
||||
int maxlen = text->maximumLength();
|
||||
|
@ -594,8 +596,8 @@ void FormLineEdit::slotRefresh(Okular::FormField *form)
|
|||
setText(text->text());
|
||||
}
|
||||
|
||||
TextAreaEdit::TextAreaEdit(Okular::FormFieldText *text, QWidget *parent)
|
||||
: KTextEdit(parent)
|
||||
TextAreaEdit::TextAreaEdit(Okular::FormFieldText *text, PageView *pageView)
|
||||
: KTextEdit(pageView->viewport())
|
||||
, FormWidgetIface(this, text)
|
||||
{
|
||||
setAcceptRichText(text->isRichText());
|
||||
|
@ -730,8 +732,8 @@ void TextAreaEdit::slotRefresh(Okular::FormField *form)
|
|||
setPlainText(text->text());
|
||||
}
|
||||
|
||||
FileEdit::FileEdit(Okular::FormFieldText *text, QWidget *parent)
|
||||
: KUrlRequester(parent)
|
||||
FileEdit::FileEdit(Okular::FormFieldText *text, PageView *pageView)
|
||||
: KUrlRequester(pageView->viewport())
|
||||
, FormWidgetIface(this, text)
|
||||
{
|
||||
setMode(KFile::File | KFile::ExistingOnly | KFile::LocalOnly);
|
||||
|
@ -839,8 +841,8 @@ void FileEdit::slotHandleFileChangedByUndoRedo(int pageNumber, Okular::FormField
|
|||
setFocus();
|
||||
}
|
||||
|
||||
ListEdit::ListEdit(Okular::FormFieldChoice *choice, QWidget *parent)
|
||||
: QListWidget(parent)
|
||||
ListEdit::ListEdit(Okular::FormFieldChoice *choice, PageView *pageView)
|
||||
: QListWidget(pageView->viewport())
|
||||
, FormWidgetIface(this, choice)
|
||||
{
|
||||
addItems(choice->choices());
|
||||
|
@ -900,8 +902,8 @@ void ListEdit::slotHandleFormListChangedByUndoRedo(int pageNumber, Okular::FormF
|
|||
setFocus();
|
||||
}
|
||||
|
||||
ComboEdit::ComboEdit(Okular::FormFieldChoice *choice, QWidget *parent)
|
||||
: QComboBox(parent)
|
||||
ComboEdit::ComboEdit(Okular::FormFieldChoice *choice, PageView *pageView)
|
||||
: QComboBox(pageView->viewport())
|
||||
, FormWidgetIface(this, choice)
|
||||
{
|
||||
addItems(choice->choices());
|
||||
|
@ -1035,15 +1037,20 @@ bool ComboEdit::event(QEvent *e)
|
|||
return QComboBox::event(e);
|
||||
}
|
||||
|
||||
SignatureEdit::SignatureEdit(Okular::FormFieldSignature *signature, QWidget *parent)
|
||||
: QAbstractButton(parent)
|
||||
SignatureEdit::SignatureEdit(Okular::FormFieldSignature *signature, PageView *pageView)
|
||||
: QAbstractButton(pageView->viewport())
|
||||
, FormWidgetIface(this, signature)
|
||||
, m_widgetPressed(false)
|
||||
, m_dummyMode(false)
|
||||
, m_wasVisible(false)
|
||||
{
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
connect(this, &SignatureEdit::clicked, this, &SignatureEdit::slotViewProperties);
|
||||
if (signature->signatureType() == Okular::FormFieldSignature::UnsignedSignature) {
|
||||
setToolTip(i18n("Unsigned Signature Field (Click to Sign)"));
|
||||
connect(this, &SignatureEdit::clicked, this, &SignatureEdit::signUnsignedSignature);
|
||||
} else {
|
||||
connect(this, &SignatureEdit::clicked, this, &SignatureEdit::slotViewProperties);
|
||||
}
|
||||
}
|
||||
|
||||
void SignatureEdit::setDummyMode(bool set)
|
||||
|
@ -1102,9 +1109,16 @@ bool SignatureEdit::event(QEvent *e)
|
|||
void SignatureEdit::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
QMenu *menu = new QMenu(this);
|
||||
QAction *signatureProperties = new QAction(i18n("Signature Properties"), menu);
|
||||
connect(signatureProperties, &QAction::triggered, this, &SignatureEdit::slotViewProperties);
|
||||
menu->addAction(signatureProperties);
|
||||
Okular::FormFieldSignature *formSignature = static_cast<Okular::FormFieldSignature *>(formField());
|
||||
if (formSignature->signatureType() == Okular::FormFieldSignature::UnsignedSignature) {
|
||||
QAction *signAction = new QAction(i18n("&Sign..."), menu);
|
||||
connect(signAction, &QAction::triggered, this, &SignatureEdit::signUnsignedSignature);
|
||||
menu->addAction(signAction);
|
||||
} else {
|
||||
QAction *signatureProperties = new QAction(i18n("Signature Properties"), menu);
|
||||
connect(signatureProperties, &QAction::triggered, this, &SignatureEdit::slotViewProperties);
|
||||
menu->addAction(signatureProperties);
|
||||
}
|
||||
menu->exec(event->globalPos());
|
||||
delete menu;
|
||||
}
|
||||
|
@ -1139,6 +1153,16 @@ void SignatureEdit::slotViewProperties()
|
|||
propDlg.exec();
|
||||
}
|
||||
|
||||
void SignatureEdit::signUnsignedSignature()
|
||||
{
|
||||
if (m_dummyMode)
|
||||
return;
|
||||
|
||||
Okular::FormFieldSignature *formSignature = static_cast<Okular::FormFieldSignature *>(formField());
|
||||
PageView *pageView = static_cast<PageView *>(parent()->parent());
|
||||
SignatureGuiUtils::signUnsignedSignature(formSignature, pageView, pageView->document());
|
||||
}
|
||||
|
||||
// Code for additional action handling.
|
||||
// Challenge: Change preprocessor magic to C++ magic!
|
||||
//
|
||||
|
|
|
@ -26,6 +26,7 @@ class ComboEdit;
|
|||
class QMenu;
|
||||
class QButtonGroup;
|
||||
class FormWidgetIface;
|
||||
class PageView;
|
||||
class PageViewItem;
|
||||
class RadioButtonEdit;
|
||||
class QEvent;
|
||||
|
@ -121,7 +122,7 @@ private:
|
|||
class FormWidgetFactory
|
||||
{
|
||||
public:
|
||||
static FormWidgetIface *createWidget(Okular::FormField *ff, QWidget *parent = nullptr);
|
||||
static FormWidgetIface *createWidget(Okular::FormField *ff, PageView *pageView);
|
||||
};
|
||||
|
||||
class FormWidgetIface
|
||||
|
@ -171,7 +172,7 @@ class PushButtonEdit : public QPushButton, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PushButtonEdit(Okular::FormFieldButton *button, QWidget *parent = nullptr);
|
||||
explicit PushButtonEdit(Okular::FormFieldButton *button, PageView *pageView);
|
||||
|
||||
DECLARE_ADDITIONAL_ACTIONS
|
||||
};
|
||||
|
@ -181,7 +182,7 @@ class CheckBoxEdit : public QCheckBox, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CheckBoxEdit(Okular::FormFieldButton *button, QWidget *parent = nullptr);
|
||||
explicit CheckBoxEdit(Okular::FormFieldButton *button, PageView *pageView);
|
||||
|
||||
// reimplemented from FormWidgetIface
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
|
@ -198,7 +199,7 @@ class RadioButtonEdit : public QRadioButton, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RadioButtonEdit(Okular::FormFieldButton *button, QWidget *parent = nullptr);
|
||||
explicit RadioButtonEdit(Okular::FormFieldButton *button, PageView *pageView);
|
||||
|
||||
// reimplemented from FormWidgetIface
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
|
@ -210,7 +211,7 @@ class FormLineEdit : public QLineEdit, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FormLineEdit(Okular::FormFieldText *text, QWidget *parent = nullptr);
|
||||
explicit FormLineEdit(Okular::FormFieldText *text, PageView *pageView);
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
bool event(QEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
@ -235,7 +236,7 @@ class TextAreaEdit : public KTextEdit, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TextAreaEdit(Okular::FormFieldText *text, QWidget *parent = nullptr);
|
||||
explicit TextAreaEdit(Okular::FormFieldText *text, PageView *pageView);
|
||||
~TextAreaEdit() override;
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
bool event(QEvent *e) override;
|
||||
|
@ -262,7 +263,7 @@ class FileEdit : public KUrlRequester, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FileEdit(Okular::FormFieldText *text, QWidget *parent = nullptr);
|
||||
explicit FileEdit(Okular::FormFieldText *text, PageView *pageView);
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
|
||||
protected:
|
||||
|
@ -283,7 +284,7 @@ class ListEdit : public QListWidget, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ListEdit(Okular::FormFieldChoice *choice, QWidget *parent = nullptr);
|
||||
explicit ListEdit(Okular::FormFieldChoice *choice, PageView *pageView);
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
@ -297,7 +298,7 @@ class ComboEdit : public QComboBox, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ComboEdit(Okular::FormFieldChoice *choice, QWidget *parent = nullptr);
|
||||
explicit ComboEdit(Okular::FormFieldChoice *choice, PageView *pageView);
|
||||
void setFormWidgetsController(FormWidgetsController *controller) override;
|
||||
bool event(QEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
|
@ -317,7 +318,7 @@ class SignatureEdit : public QAbstractButton, public FormWidgetIface
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SignatureEdit(Okular::FormFieldSignature *signature, QWidget *parent = nullptr);
|
||||
explicit SignatureEdit(Okular::FormFieldSignature *signature, PageView *pageView);
|
||||
|
||||
// This will be called when an item in signature panel is clicked. Calling it changes the
|
||||
// widget state. If this widget was visible prior to calling this then background
|
||||
|
@ -332,6 +333,7 @@ protected:
|
|||
|
||||
private Q_SLOTS:
|
||||
void slotViewProperties();
|
||||
void signUnsignedSignature();
|
||||
|
||||
private:
|
||||
bool m_widgetPressed;
|
||||
|
|
|
@ -1252,7 +1252,7 @@ void PageView::notifySetup(const QVector<Okular::Page *> &pageSet, int setupFlag
|
|||
#endif
|
||||
const QLinkedList<Okular::FormField *> pageFields = page->formFields();
|
||||
for (Okular::FormField *ff : pageFields) {
|
||||
FormWidgetIface *w = FormWidgetFactory::createWidget(ff, viewport());
|
||||
FormWidgetIface *w = FormWidgetFactory::createWidget(ff, this);
|
||||
if (w) {
|
||||
w->setPageItem(item);
|
||||
w->setFormWidgetsController(d->formWidgetsController());
|
||||
|
@ -4894,6 +4894,11 @@ void PageView::showNoSigningCertificatesDialog(bool nonDateValidCerts)
|
|||
}
|
||||
}
|
||||
|
||||
Okular::Document *PageView::document() const
|
||||
{
|
||||
return d->document;
|
||||
}
|
||||
|
||||
void PageView::slotSignature()
|
||||
{
|
||||
if (!d->document->isHistoryClean()) {
|
||||
|
|
|
@ -117,6 +117,8 @@ public:
|
|||
|
||||
void showNoSigningCertificatesDialog(bool nonDateValidCerts);
|
||||
|
||||
Okular::Document *document() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void copyTextSelection() const;
|
||||
void selectAll();
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <QInputDialog>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMimeDatabase>
|
||||
#include <QPainter>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
|
@ -45,6 +44,7 @@
|
|||
#include "guiutils.h"
|
||||
#include "pageview.h"
|
||||
#include "settings.h"
|
||||
#include "signatureguiutils.h"
|
||||
|
||||
/** @short PickPointEngine */
|
||||
class PickPointEngine : public AnnotatorEngine
|
||||
|
@ -354,75 +354,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
const Okular::CertificateStore *certStore = m_document->certificateStore();
|
||||
bool userCancelled, nonDateValidCerts;
|
||||
const QList<Okular::CertificateInfo *> &certs = certStore->signingCertificatesForNow(&userCancelled, &nonDateValidCerts);
|
||||
if (userCancelled) {
|
||||
const std::unique_ptr<Okular::CertificateInfo> cert = SignatureGuiUtils::getCertificateAndPasswordForSigning(m_pageView, m_document, &passToUse, &documentPassword);
|
||||
if (!cert) {
|
||||
m_aborted = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (certs.isEmpty()) {
|
||||
m_creationCompleted = false;
|
||||
clicked = false;
|
||||
m_pageView->showNoSigningCertificatesDialog(nonDateValidCerts);
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList items;
|
||||
QHash<QString, Okular::CertificateInfo *> nickToCert;
|
||||
for (auto cert : certs) {
|
||||
items.append(cert->nickName());
|
||||
nickToCert[cert->nickName()] = cert;
|
||||
}
|
||||
|
||||
bool resok = false;
|
||||
certNicknameToUse = QInputDialog::getItem(m_pageView, i18n("Select certificate to sign with"), i18n("Certificates:"), items, 0, false, &resok);
|
||||
|
||||
if (resok) {
|
||||
// I could not find any case in which i need to enter a password to use the certificate, seems that once you unlcok the firefox/NSS database
|
||||
// you don't need a password anymore, but still there's code to do that in NSS so we have code to ask for it if needed. What we do is
|
||||
// ask if the empty password is fine, if it is we don't ask the user anything, if it's not, we ask for a password
|
||||
Okular::CertificateInfo *cert = nickToCert.value(certNicknameToUse);
|
||||
bool passok = cert->checkPassword(QString());
|
||||
while (!passok) {
|
||||
const QString title = i18n("Enter password (if any) to unlock certificate: %1", certNicknameToUse);
|
||||
bool ok;
|
||||
passToUse = QInputDialog::getText(m_pageView, i18n("Enter certificate password"), title, QLineEdit::Password, QString(), &ok);
|
||||
if (ok) {
|
||||
passok = cert->checkPassword(passToUse);
|
||||
} else {
|
||||
passok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (passok) {
|
||||
certCommonName = cert->subjectInfo(Okular::CertificateInfo::CommonName);
|
||||
} else {
|
||||
certNicknameToUse.clear();
|
||||
m_aborted = true;
|
||||
}
|
||||
passToUse.clear();
|
||||
documentPassword.clear();
|
||||
} else {
|
||||
// The Cancel button has been clicked in the certificate dialog.
|
||||
certNicknameToUse.clear();
|
||||
m_aborted = true;
|
||||
}
|
||||
|
||||
if (m_document->metaData(QStringLiteral("DocumentHasPassword")).toString() == QLatin1String("yes")) {
|
||||
bool ok;
|
||||
documentPassword = QInputDialog::getText(m_pageView, i18n("Enter document password"), i18n("Enter document password"), QLineEdit::Password, QString(), &ok);
|
||||
if (!ok) {
|
||||
passToUse.clear();
|
||||
m_aborted = true;
|
||||
}
|
||||
certNicknameToUse = cert->nickName();
|
||||
certCommonName = cert->subjectInfo(Okular::CertificateInfo::CommonName);
|
||||
}
|
||||
|
||||
m_creationCompleted = false;
|
||||
clicked = false;
|
||||
|
||||
qDeleteAll(certs);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -1041,18 +985,7 @@ QRect PageViewAnnotator::performRouteMouseOrTabletEvent(const AnnotatorEngine::E
|
|||
if (signatureMode()) {
|
||||
auto signEngine = static_cast<PickPointEngineSignature *>(m_engine);
|
||||
if (signEngine->isAccepted()) {
|
||||
QMimeDatabase db;
|
||||
const QString typeName = m_document->documentInfo().get(Okular::DocumentInfo::MimeType);
|
||||
const QMimeType mimeType = db.mimeTypeForName(typeName);
|
||||
const QString mimeTypeFilter = i18nc("File type name and pattern", "%1 (%2)", mimeType.comment(), mimeType.globPatterns().join(QLatin1Char(' ')));
|
||||
|
||||
const QUrl currentFileUrl = m_document->currentDocument();
|
||||
const QFileInfo currentFileInfo(currentFileUrl.fileName());
|
||||
const QString localFilePathIfAny = currentFileUrl.isLocalFile() ? QFileInfo(currentFileUrl.path()).canonicalPath() + QLatin1Char('/') : QString();
|
||||
const QString newFileName =
|
||||
localFilePathIfAny + i18nc("Used when suggesting a new name for a digitally signed file. %1 is the old file name and %2 it's extension", "%1_signed.%2", currentFileInfo.baseName(), currentFileInfo.completeSuffix());
|
||||
|
||||
const QString newFilePath = QFileDialog::getSaveFileName(m_pageView, i18n("Save Signed File As"), newFileName, mimeTypeFilter);
|
||||
const QString newFilePath = SignatureGuiUtils::getFileNameForNewSignedFile(m_pageView, m_document);
|
||||
|
||||
if (!newFilePath.isEmpty()) {
|
||||
const bool success = static_cast<PickPointEngineSignature *>(m_engine)->sign(newFilePath);
|
||||
|
|
|
@ -1589,14 +1589,22 @@ bool Part::openFile()
|
|||
} else {
|
||||
const QVector<const Okular::FormFieldSignature *> signatureFormFields = SignatureGuiUtils::getSignatureFormFields(m_document);
|
||||
bool allSignaturesValid = true;
|
||||
bool anySignatureUnsigned = false;
|
||||
for (const Okular::FormFieldSignature *signature : signatureFormFields) {
|
||||
const Okular::SignatureInfo &info = signature->signatureInfo();
|
||||
if (info.signatureStatus() != SignatureInfo::SignatureValid) {
|
||||
allSignaturesValid = false;
|
||||
if (signature->signatureType() == Okular::FormFieldSignature::UnsignedSignature) {
|
||||
anySignatureUnsigned = true;
|
||||
} else {
|
||||
const Okular::SignatureInfo &info = signature->signatureInfo();
|
||||
if (info.signatureStatus() != SignatureInfo::SignatureValid) {
|
||||
allSignaturesValid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allSignaturesValid) {
|
||||
if (anySignatureUnsigned) {
|
||||
m_signatureMessage->setMessageType(KMessageWidget::Information);
|
||||
m_signatureMessage->setText(i18n("This document has unsigned signature fields."));
|
||||
} else if (allSignaturesValid) {
|
||||
if (signatureFormFields.last()->signatureInfo().signsTotalDocument()) {
|
||||
m_signatureMessage->setMessageType(KMessageWidget::Information);
|
||||
m_signatureMessage->setText(i18n("This document is digitally signed."));
|
||||
|
|
|
@ -6,11 +6,18 @@
|
|||
|
||||
#include "signatureguiutils.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QInputDialog>
|
||||
#include <QMimeDatabase>
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KMessageBox>
|
||||
|
||||
#include "core/document.h"
|
||||
#include "core/form.h"
|
||||
#include "core/page.h"
|
||||
#include "pageview.h"
|
||||
|
||||
namespace SignatureGuiUtils
|
||||
{
|
||||
|
@ -145,4 +152,106 @@ QString getReadableKeyUsageNewLineSeparated(Okular::CertificateInfo::KeyUsageExt
|
|||
return getReadableKeyUsage(kuExtensions, QStringLiteral("\n"));
|
||||
}
|
||||
|
||||
std::unique_ptr<Okular::CertificateInfo> getCertificateAndPasswordForSigning(PageView *pageView, Okular::Document *doc, QString *password, QString *documentPassword)
|
||||
{
|
||||
const Okular::CertificateStore *certStore = doc->certificateStore();
|
||||
bool userCancelled, nonDateValidCerts;
|
||||
QList<Okular::CertificateInfo *> certs = certStore->signingCertificatesForNow(&userCancelled, &nonDateValidCerts);
|
||||
if (userCancelled) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (certs.isEmpty()) {
|
||||
pageView->showNoSigningCertificatesDialog(nonDateValidCerts);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QStringList items;
|
||||
QHash<QString, Okular::CertificateInfo *> nickToCert;
|
||||
for (auto cert : qAsConst(certs)) {
|
||||
items.append(cert->nickName());
|
||||
nickToCert[cert->nickName()] = cert;
|
||||
}
|
||||
|
||||
bool resok = false;
|
||||
const QString certNicknameToUse = QInputDialog::getItem(pageView, i18n("Select certificate to sign with"), i18n("Certificates:"), items, 0, false, &resok);
|
||||
|
||||
if (!resok) {
|
||||
qDeleteAll(certs);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// I could not find any case in which i need to enter a password to use the certificate, seems that once you unlcok the firefox/NSS database
|
||||
// you don't need a password anymore, but still there's code to do that in NSS so we have code to ask for it if needed. What we do is
|
||||
// ask if the empty password is fine, if it is we don't ask the user anything, if it's not, we ask for a password
|
||||
Okular::CertificateInfo *cert = nickToCert.value(certNicknameToUse);
|
||||
bool passok = cert->checkPassword(*password);
|
||||
while (!passok) {
|
||||
const QString title = i18n("Enter password (if any) to unlock certificate: %1", certNicknameToUse);
|
||||
bool ok;
|
||||
*password = QInputDialog::getText(pageView, i18n("Enter certificate password"), title, QLineEdit::Password, QString(), &ok);
|
||||
if (ok) {
|
||||
passok = cert->checkPassword(*password);
|
||||
} else {
|
||||
passok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doc->metaData(QStringLiteral("DocumentHasPassword")).toString() == QLatin1String("yes")) {
|
||||
*documentPassword = QInputDialog::getText(pageView, i18n("Enter document password"), i18n("Enter document password"), QLineEdit::Password, QString(), &passok);
|
||||
}
|
||||
|
||||
if (passok) {
|
||||
certs.removeOne(cert);
|
||||
}
|
||||
qDeleteAll(certs);
|
||||
|
||||
return passok ? std::unique_ptr<Okular::CertificateInfo>(cert) : std::unique_ptr<Okular::CertificateInfo>();
|
||||
}
|
||||
|
||||
QString getFileNameForNewSignedFile(PageView *pageView, Okular::Document *doc)
|
||||
{
|
||||
QMimeDatabase db;
|
||||
const QString typeName = doc->documentInfo().get(Okular::DocumentInfo::MimeType);
|
||||
const QMimeType mimeType = db.mimeTypeForName(typeName);
|
||||
const QString mimeTypeFilter = i18nc("File type name and pattern", "%1 (%2)", mimeType.comment(), mimeType.globPatterns().join(QLatin1Char(' ')));
|
||||
|
||||
const QUrl currentFileUrl = doc->currentDocument();
|
||||
const QFileInfo currentFileInfo(currentFileUrl.fileName());
|
||||
const QString localFilePathIfAny = currentFileUrl.isLocalFile() ? QFileInfo(currentFileUrl.path()).canonicalPath() + QLatin1Char('/') : QString();
|
||||
const QString newFileName =
|
||||
localFilePathIfAny + i18nc("Used when suggesting a new name for a digitally signed file. %1 is the old file name and %2 it's extension", "%1_signed.%2", currentFileInfo.baseName(), currentFileInfo.completeSuffix());
|
||||
|
||||
return QFileDialog::getSaveFileName(pageView, i18n("Save Signed File As"), newFileName, mimeTypeFilter);
|
||||
}
|
||||
|
||||
void signUnsignedSignature(const Okular::FormFieldSignature *form, PageView *pageView, Okular::Document *doc)
|
||||
{
|
||||
Q_ASSERT(form && form->signatureType() == Okular::FormFieldSignature::UnsignedSignature);
|
||||
QString password, documentPassword;
|
||||
const std::unique_ptr<Okular::CertificateInfo> cert = SignatureGuiUtils::getCertificateAndPasswordForSigning(pageView, doc, &password, &documentPassword);
|
||||
if (!cert) {
|
||||
return;
|
||||
}
|
||||
|
||||
Okular::NewSignatureData data;
|
||||
data.setCertNickname(cert->nickName());
|
||||
data.setCertSubjectCommonName(cert->subjectInfo(Okular::CertificateInfo::CommonName));
|
||||
data.setPassword(password);
|
||||
data.setDocumentPassword(documentPassword);
|
||||
password.clear();
|
||||
documentPassword.clear();
|
||||
|
||||
const QString newFilePath = SignatureGuiUtils::getFileNameForNewSignedFile(pageView, doc);
|
||||
|
||||
if (!newFilePath.isEmpty()) {
|
||||
const bool success = form->sign(data, newFilePath);
|
||||
if (success) {
|
||||
emit pageView->requestOpenFile(newFilePath, form->page()->number() + 1);
|
||||
} else {
|
||||
KMessageBox::error(pageView, i18nc("%1 is a file path", "Could not sign. Invalid certificate password or could not write to '%1'", newFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
#include "core/signatureutils.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class PageView;
|
||||
|
||||
namespace Okular
|
||||
{
|
||||
class Document;
|
||||
|
@ -30,6 +34,9 @@ QString getReadablePublicKeyType(Okular::CertificateInfo::PublicKeyType type);
|
|||
QString getReadableKeyUsageCommaSeparated(Okular::CertificateInfo::KeyUsageExtensions kuExtensions);
|
||||
QString getReadableKeyUsageNewLineSeparated(Okular::CertificateInfo::KeyUsageExtensions kuExtensions);
|
||||
|
||||
std::unique_ptr<Okular::CertificateInfo> getCertificateAndPasswordForSigning(PageView *pageView, Okular::Document *doc, QString *password, QString *documentPassword);
|
||||
QString getFileNameForNewSignedFile(PageView *pageView, Okular::Document *doc);
|
||||
void signUnsignedSignature(const Okular::FormFieldSignature *form, PageView *pageView, Okular::Document *doc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -124,32 +124,43 @@ void SignatureModelPrivate::notifySetup(const QVector<Okular::Page *> &pages, in
|
|||
}
|
||||
|
||||
int revNumber = 1;
|
||||
int unsignedSignatureNumber = 1;
|
||||
const QVector<const Okular::FormFieldSignature *> signatureFormFields = SignatureGuiUtils::getSignatureFormFields(document);
|
||||
for (const Okular::FormFieldSignature *sf : signatureFormFields) {
|
||||
const Okular::SignatureInfo &info = sf->signatureInfo();
|
||||
|
||||
const int pageNumber = sf->page()->number();
|
||||
|
||||
// based on whether or not signature form is a nullptr it is decided if clicking on an item should change the viewport.
|
||||
auto *parentItem = new SignatureItem(root, sf, SignatureItem::RevisionInfo, pageNumber);
|
||||
parentItem->displayString = i18n("Rev. %1: Signed By %2", revNumber, info.signerName());
|
||||
if (sf->signatureType() == Okular::FormFieldSignature::UnsignedSignature) {
|
||||
auto *parentItem = new SignatureItem(root, sf, SignatureItem::RevisionInfo, pageNumber);
|
||||
parentItem->displayString = i18n("Unsigned Signature %1", unsignedSignatureNumber);
|
||||
|
||||
auto childItem1 = new SignatureItem(parentItem, nullptr, SignatureItem::ValidityStatus, pageNumber);
|
||||
childItem1->displayString = SignatureGuiUtils::getReadableSignatureStatus(info.signatureStatus());
|
||||
auto childItem = new SignatureItem(parentItem, sf, SignatureItem::FieldInfo, pageNumber);
|
||||
childItem->displayString = i18n("Field: %1 on page %2", sf->name(), pageNumber + 1);
|
||||
|
||||
auto childItem2 = new SignatureItem(parentItem, nullptr, SignatureItem::SigningTime, pageNumber);
|
||||
childItem2->displayString = i18n("Signing Time: %1", info.signingTime().toString(Qt::DefaultLocaleLongDate));
|
||||
++unsignedSignatureNumber;
|
||||
} else {
|
||||
const Okular::SignatureInfo &info = sf->signatureInfo();
|
||||
|
||||
const QString reason = info.reason();
|
||||
if (!reason.isEmpty()) {
|
||||
auto childItem3 = new SignatureItem(parentItem, nullptr, SignatureItem::Reason, pageNumber);
|
||||
childItem3->displayString = i18n("Reason: %1", reason);
|
||||
// based on whether or not signature form is a nullptr it is decided if clicking on an item should change the viewport.
|
||||
auto *parentItem = new SignatureItem(root, sf, SignatureItem::RevisionInfo, pageNumber);
|
||||
parentItem->displayString = i18n("Rev. %1: Signed By %2", revNumber, info.signerName());
|
||||
|
||||
auto childItem1 = new SignatureItem(parentItem, nullptr, SignatureItem::ValidityStatus, pageNumber);
|
||||
childItem1->displayString = SignatureGuiUtils::getReadableSignatureStatus(info.signatureStatus());
|
||||
|
||||
auto childItem2 = new SignatureItem(parentItem, nullptr, SignatureItem::SigningTime, pageNumber);
|
||||
childItem2->displayString = i18n("Signing Time: %1", info.signingTime().toString(Qt::DefaultLocaleLongDate));
|
||||
|
||||
const QString reason = info.reason();
|
||||
if (!reason.isEmpty()) {
|
||||
auto childItem3 = new SignatureItem(parentItem, nullptr, SignatureItem::Reason, pageNumber);
|
||||
childItem3->displayString = i18n("Reason: %1", reason);
|
||||
}
|
||||
|
||||
auto childItem4 = new SignatureItem(parentItem, sf, SignatureItem::FieldInfo, pageNumber);
|
||||
childItem4->displayString = i18n("Field: %1 on page %2", sf->name(), pageNumber + 1);
|
||||
|
||||
++revNumber;
|
||||
}
|
||||
|
||||
auto childItem4 = new SignatureItem(parentItem, sf, SignatureItem::FieldInfo, pageNumber);
|
||||
childItem4->displayString = i18n("Field: %1 on page %2", sf->name(), pageNumber + 1);
|
||||
|
||||
++revNumber;
|
||||
}
|
||||
q->endResetModel();
|
||||
}
|
||||
|
|
|
@ -91,9 +91,15 @@ void SignaturePanel::slotShowContextMenu()
|
|||
return;
|
||||
|
||||
QMenu *menu = new QMenu(this);
|
||||
QAction *sigProp = new QAction(i18n("Properties"), menu);
|
||||
connect(sigProp, &QAction::triggered, this, &SignaturePanel::slotViewProperties);
|
||||
menu->addAction(sigProp);
|
||||
if (d->m_currentForm->signatureType() == Okular::FormFieldSignature::UnsignedSignature) {
|
||||
QAction *signAction = new QAction(i18n("&Sign..."), menu);
|
||||
connect(signAction, &QAction::triggered, this, &SignaturePanel::signUnsignedSignature);
|
||||
menu->addAction(signAction);
|
||||
} else {
|
||||
QAction *sigProp = new QAction(i18n("Properties"), menu);
|
||||
connect(sigProp, &QAction::triggered, this, &SignaturePanel::slotViewProperties);
|
||||
menu->addAction(sigProp);
|
||||
}
|
||||
menu->exec(QCursor::pos());
|
||||
delete menu;
|
||||
}
|
||||
|
@ -105,6 +111,12 @@ void SignaturePanel::slotViewProperties()
|
|||
propDlg.exec();
|
||||
}
|
||||
|
||||
void SignaturePanel::signUnsignedSignature()
|
||||
{
|
||||
Q_D(SignaturePanel);
|
||||
SignatureGuiUtils::signUnsignedSignature(d->m_currentForm, d->m_pageView, d->m_document);
|
||||
}
|
||||
|
||||
void SignaturePanel::notifySetup(const QVector<Okular::Page *> & /*pages*/, int setupFlags)
|
||||
{
|
||||
if (!(setupFlags & Okular::DocumentObserver::UrlChanged))
|
||||
|
|
|
@ -40,6 +40,7 @@ private Q_SLOTS:
|
|||
void activated(const QModelIndex &);
|
||||
void slotShowContextMenu();
|
||||
void slotViewProperties();
|
||||
void signUnsignedSignature();
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(SignaturePanel)
|
||||
|
|
Loading…
Reference in a new issue