diff --git a/core/signatureutils.cpp b/core/signatureutils.cpp index dbf925db6..53da00c6e 100644 --- a/core/signatureutils.cpp +++ b/core/signatureutils.cpp @@ -1,157 +1,152 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "signatureutils.h" using namespace Okular; CertificateInfo::CertificateInfo() { } CertificateInfo::~CertificateInfo() { } -Q_DECLARE_OPERATORS_FOR_FLAGS( CertificateInfo::KeyUsageExtensions ) +Q_DECLARE_OPERATORS_FOR_FLAGS( CertificateInfo::KeyUsages ) -bool CertificateInfo::isNull() const +QByteArray CertificateInfo::version() const { - return true; -} - -int CertificateInfo::version() const -{ - return -1; + return QByteArray(); } -QByteArray CertificateInfo::serialNumber() const +QString CertificateInfo::issuerName() const { - return QByteArray(); + return QString(); } -QString CertificateInfo::issuerInfo(EntityInfoKey) const +QString CertificateInfo::issuerDN() const { return QString(); } -QString CertificateInfo::subjectInfo(EntityInfoKey) const +QByteArray CertificateInfo::serialNumber() const { - return QString(); + return QByteArray(); } QDateTime CertificateInfo::validityStart() const { return QDateTime(); } QDateTime CertificateInfo::validityEnd() const { return QDateTime(); } -CertificateInfo::KeyUsageExtensions CertificateInfo::keyUsageExtensions() const +CertificateInfo::KeyUsages CertificateInfo::keyUsages() const { return KuNone; } QByteArray CertificateInfo::publicKey() const { return QByteArray(); } CertificateInfo::PublicKeyType CertificateInfo::publicKeyType() const { return OtherKey; } int CertificateInfo::publicKeyStrength() const { return -1; } bool CertificateInfo::isSelfSigned() const { return false; } QByteArray CertificateInfo::certificateData() const { return QByteArray(); } SignatureInfo::SignatureInfo() { } SignatureInfo::~SignatureInfo() { } SignatureInfo::SignatureStatus SignatureInfo::signatureStatus() const { return SignatureStatusUnknown; } SignatureInfo::CertificateStatus SignatureInfo::certificateStatus() const { return CertificateStatusUnknown; } SignatureInfo::HashAlgorithm SignatureInfo::hashAlgorithm() const { return HashAlgorithmUnknown; } -QString SignatureInfo::signerName() const -{ - return QString(); -} - -QString SignatureInfo::signerSubjectDN() const +QString SignatureInfo::subjectName() const { return QString(); } -QString SignatureInfo::location() const -{ - return QString(); -} - -QString SignatureInfo::reason() const +QString SignatureInfo::subjectDN() const { return QString(); } QDateTime SignatureInfo::signingTime() const { return QDateTime(); } QByteArray SignatureInfo::signature() const { return QByteArray(); } QList SignatureInfo::signedRangeBounds() const { return QList(); } bool SignatureInfo::signsTotalDocument() const { return false; } +QString SignatureInfo::location() const +{ + return QString(); +} + +QString SignatureInfo::reason() const +{ + return QString(); +} + CertificateInfo *SignatureInfo::certificateInfo() const { return nullptr; } diff --git a/core/signatureutils.h b/core/signatureutils.h index 1f27de662..4cbc6118b 100644 --- a/core/signatureutils.h +++ b/core/signatureutils.h @@ -1,276 +1,261 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef OKULAR_SIGNATUREINFO_H #define OKULAR_SIGNATUREINFO_H #include "okularcore_export.h" #include #include #include #include #include namespace Okular { class CertificateInfoPrivate; class SignatureInfoPrivate; /** * @short A helper class to store information x509 digital certificate */ class OKULARCORE_EXPORT CertificateInfo { public: /** * The algorithm of public key. */ enum PublicKeyType { RsaKey, DsaKey, EcKey, OtherKey }; /** - * Certificate key usage extensions. + * Certificate key usage. */ - enum KeyUsageExtension + enum KeyUsage { - KuDigitalSignature = 0x80, - KuNonRepudiation = 0x40, - KuKeyEncipherment = 0x20, - KuDataEncipherment = 0x10, - KuKeyAgreement = 0x08, - KuKeyCertSign = 0x04, - KuClrSign = 0x02, - KuEncipherOnly = 0x01, - KuNone = 0x00 - }; - Q_DECLARE_FLAGS( KeyUsageExtensions, KeyUsageExtension ) - - /** - * Predefined keys for elements in an entity's distinguished name. - */ - enum EntityInfoKey - { - CommonName, - DistinguishedName, - EmailAddress, - Organization, + KuNone = 0, + KuDigitalSignature = 1, + KuNonRepudiation = 2, + KuKeyEncipherment = 4, + KuDataEncipherment = 8, + KuKeyAgreement = 16, + KuKeyCertSign = 32, + KuClrSign = 64, + KuEncipherOnly = 128 }; + Q_DECLARE_FLAGS( KeyUsages, KeyUsage ) /** * Destructor */ virtual ~CertificateInfo(); /** - * Returns true if certificate has no contents otherwise returns false. + * The certificate version string in hex encoding. */ - virtual bool isNull() const; + virtual QByteArray version() const; /** - * The certificate version string. + * The common name of certificate issuer. */ - virtual int version() const; + virtual QString issuerName() const; /** - * The certificate serial number. + * The distinguished name of certificate issuer. */ - virtual QByteArray serialNumber() const; + virtual QString issuerDN() const; /** - * Information about the issuer. + The hex encoded certificate serial number. */ - virtual QString issuerInfo(EntityInfoKey key) const; - - /** - * Information about the subject - */ - virtual QString subjectInfo(EntityInfoKey key) const; + virtual QByteArray serialNumber() const; /** - * The date-time when certificate becomes valid. - */ + The date-time when certificate becomes valid. + */ virtual QDateTime validityStart() const; /** * The date-time when certificate expires. */ virtual QDateTime validityEnd() const; /** - * The uses allowed for the certificate. + * The key usages of certificate. */ - virtual KeyUsageExtensions keyUsageExtensions() const; + virtual KeyUsages keyUsages() const; /** * The public key value. */ virtual QByteArray publicKey() const; /** * The public key type. */ virtual PublicKeyType publicKeyType() const; /** - * The strength of public key in bits. + * The strength of public key in bits or -1 in case + * key type is 'OtherKey'. */ virtual int publicKeyStrength() const; /** - * Returns true if certificate is self-signed otherwise returns false. + * Returns true if certificate is self signed; otherwise returns false. */ virtual bool isSelfSigned() const; /** * The DER encoded certificate. */ virtual QByteArray certificateData() const; protected: CertificateInfo(); private: Q_DISABLE_COPY( CertificateInfo ) }; /** * @short A helper class to store information about digital signature */ class OKULARCORE_EXPORT SignatureInfo { public: /** * The verfication result of the signature. */ enum SignatureStatus { SignatureStatusUnknown, ///< The signature status is unknown for some reason. SignatureValid, ///< The signature is cryptographically valid. SignatureInvalid, ///< The signature is cryptographically invalid. SignatureDigestMismatch, ///< The document content was changed after the signature was applied. SignatureDecodingError, ///< The signature CMS/PKCS7 structure is malformed. SignatureGenericError, ///< The signature could not be verified. SignatureNotFound, ///< The requested signature is not present in the document. SignatureNotVerified ///< The signature is not yet verified. }; /** * The verification result of the certificate. */ enum CertificateStatus { CertificateStatusUnknown, ///< The certificate status is unknown for some reason. CertificateTrusted, ///< The certificate is considered trusted. CertificateUntrustedIssuer, ///< The issuer of this certificate has been marked as untrusted by the user. CertificateUnknownIssuer, ///< The certificate trust chain has not finished in a trusted root certificate. CertificateRevoked, ///< The certificate was revoked by the issuing certificate authority. CertificateExpired, ///< The signing time is outside the validity bounds of this certificate. CertificateGenericError, ///< The certificate could not be verified. CertificateNotVerified ///< The certificate is not yet verified. }; /** * The hash algorithm of the signature */ enum HashAlgorithm { HashAlgorithmUnknown, HashAlgorithmMd2, HashAlgorithmMd5, HashAlgorithmSha1, HashAlgorithmSha256, HashAlgorithmSha384, HashAlgorithmSha512, HashAlgorithmSha224 }; /** * Destructor. */ virtual ~SignatureInfo(); /** * The signature status of the signature. */ virtual SignatureStatus signatureStatus() const; /** * The certificate status of the signature. */ virtual CertificateStatus certificateStatus() const; /** * The signer subject common name associated with the signature. */ - virtual QString signerName() const; + virtual QString subjectName() const; /** * The signer subject distinguished name associated with the signature. */ - virtual QString signerSubjectDN() const; - - /** - * Get signing location. - */ - virtual QString location() const; - - /** - * Get signing reason. - */ - virtual QString reason() const; + virtual QString subjectDN() const; /** * The the hash algorithm used for the signature. */ virtual HashAlgorithm hashAlgorithm() const; /** * The signing time associated with the signature. */ virtual QDateTime signingTime() const; /** * Get the signature binary data. */ virtual QByteArray signature() const; /** * Get the bounds of the ranges of the document which are signed. */ virtual QList signedRangeBounds() const; /** * Checks whether the signature authenticates the total document * except for the signature itself. */ virtual bool signsTotalDocument() const; + /** + * Get location. + */ + virtual QString location() const; + + /** + * Get signing reason. + */ + virtual QString reason() const; + /** * Get certificate details. */ virtual CertificateInfo *certificateInfo() const; protected: SignatureInfo(); private: Q_DISABLE_COPY( SignatureInfo ) }; } #endif diff --git a/generators/poppler/pdfsignatureutils.cpp b/generators/poppler/pdfsignatureutils.cpp index 129305b64..84c5b953d 100644 --- a/generators/poppler/pdfsignatureutils.cpp +++ b/generators/poppler/pdfsignatureutils.cpp @@ -1,240 +1,235 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "pdfsignatureutils.h" PopplerCertificateInfo::PopplerCertificateInfo( const Poppler::CertificateInfo &info ) : m_info( new Poppler::CertificateInfo( nullptr ) ) { *m_info = info; } PopplerCertificateInfo::~PopplerCertificateInfo() { delete m_info; } -bool PopplerCertificateInfo::isNull() const -{ - return m_info->isNull(); -} - -int PopplerCertificateInfo::version() const +QByteArray PopplerCertificateInfo::version() const { return m_info->version(); } -QByteArray PopplerCertificateInfo::serialNumber() const +QString PopplerCertificateInfo::issuerName() const { - return m_info->serialNumber(); + return m_info->issuerName(); } -QString PopplerCertificateInfo::issuerInfo( PopplerCertificateInfo::EntityInfoKey key ) const +QString PopplerCertificateInfo::issuerDN() const { - return m_info->issuerInfo(static_cast( key )); + return m_info->issuerDN(); } -QString PopplerCertificateInfo::subjectInfo( PopplerCertificateInfo::EntityInfoKey key ) const +QByteArray PopplerCertificateInfo::serialNumber() const { - return m_info->subjectInfo(static_cast( key )); + return m_info->serialNumber(); } QDateTime PopplerCertificateInfo::validityStart() const { return m_info->validityStart(); } QDateTime PopplerCertificateInfo::validityEnd() const { return m_info->validityEnd(); } -PopplerCertificateInfo::KeyUsageExtensions PopplerCertificateInfo::keyUsageExtensions() const +PopplerCertificateInfo::KeyUsages PopplerCertificateInfo::keyUsages() const { - Poppler::CertificateInfo::KeyUsageExtensions popplerKu = m_info->keyUsageExtensions(); - KeyUsageExtensions ku = KuNone; + Poppler::CertificateInfo::KeyUsages popplerKu = m_info->keyUsages(); + KeyUsages ku = KuNone; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuDigitalSignature ) ) ku |= KuDigitalSignature; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuNonRepudiation ) ) ku |= KuNonRepudiation; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuKeyEncipherment ) ) ku |= KuKeyEncipherment; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuDataEncipherment ) ) ku |= KuDataEncipherment; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuKeyAgreement ) ) ku |= KuKeyAgreement; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuKeyCertSign ) ) ku |= KuKeyCertSign; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuClrSign ) ) ku |= KuClrSign; if ( popplerKu.testFlag( Poppler::CertificateInfo::KuEncipherOnly ) ) ku |= KuEncipherOnly; return ku; } QByteArray PopplerCertificateInfo::publicKey() const { return m_info->publicKey(); } PopplerCertificateInfo::PublicKeyType PopplerCertificateInfo::publicKeyType() const { switch ( m_info->publicKeyType() ) { case Poppler::CertificateInfo::RsaKey: return RsaKey; case Poppler::CertificateInfo::DsaKey: return DsaKey; case Poppler::CertificateInfo::EcKey: return EcKey; case Poppler::CertificateInfo::OtherKey: return OtherKey; } } int PopplerCertificateInfo::publicKeyStrength() const { return m_info->publicKeyStrength(); } bool PopplerCertificateInfo::isSelfSigned() const { return m_info->isSelfSigned(); } QByteArray PopplerCertificateInfo::certificateData() const { return m_info->certificateData(); } PopplerSignatureInfo::PopplerSignatureInfo( const Poppler::SignatureValidationInfo &info ) : m_info( new Poppler::SignatureValidationInfo( nullptr ) ) { *m_info = info; } PopplerSignatureInfo::~PopplerSignatureInfo() { delete m_info; } PopplerSignatureInfo::SignatureStatus PopplerSignatureInfo::signatureStatus() const { switch ( m_info->signatureStatus() ) { case Poppler::SignatureValidationInfo::SignatureValid: return SignatureValid; case Poppler::SignatureValidationInfo::SignatureInvalid: return SignatureInvalid; case Poppler::SignatureValidationInfo::SignatureDigestMismatch: return SignatureDigestMismatch; case Poppler::SignatureValidationInfo::SignatureDecodingError: return SignatureDecodingError; case Poppler::SignatureValidationInfo::SignatureGenericError: return SignatureGenericError; case Poppler::SignatureValidationInfo::SignatureNotFound: return SignatureNotFound; case Poppler::SignatureValidationInfo::SignatureNotVerified: return SignatureNotVerified; default: return SignatureStatusUnknown; } } PopplerSignatureInfo::CertificateStatus PopplerSignatureInfo::certificateStatus() const { switch ( m_info->certificateStatus() ) { case Poppler::SignatureValidationInfo::CertificateTrusted: return CertificateTrusted; case Poppler::SignatureValidationInfo::CertificateUntrustedIssuer: return CertificateUntrustedIssuer; case Poppler::SignatureValidationInfo::CertificateUnknownIssuer: return CertificateUnknownIssuer; case Poppler::SignatureValidationInfo::CertificateRevoked: return CertificateRevoked; case Poppler::SignatureValidationInfo::CertificateExpired: return CertificateExpired; case Poppler::SignatureValidationInfo::CertificateGenericError: return CertificateGenericError; case Poppler::SignatureValidationInfo::CertificateNotVerified: return CertificateNotVerified; default: return CertificateStatusUnknown; } } PopplerSignatureInfo::HashAlgorithm PopplerSignatureInfo::hashAlgorithm() const { switch ( m_info->hashAlgorithm() ) { case Poppler::SignatureValidationInfo::HashAlgorithmMd2: return HashAlgorithmMd2; case Poppler::SignatureValidationInfo::HashAlgorithmMd5: return HashAlgorithmMd5; case Poppler::SignatureValidationInfo::HashAlgorithmSha1: return HashAlgorithmSha1; case Poppler::SignatureValidationInfo::HashAlgorithmSha256: return HashAlgorithmSha256; case Poppler::SignatureValidationInfo::HashAlgorithmSha384: return HashAlgorithmSha384; case Poppler::SignatureValidationInfo::HashAlgorithmSha512: return HashAlgorithmSha512; case Poppler::SignatureValidationInfo::HashAlgorithmSha224: return HashAlgorithmSha224; default: return HashAlgorithmUnknown; } } -QString PopplerSignatureInfo::signerName() const +QString PopplerSignatureInfo::subjectName() const { return m_info->signerName(); } -QString PopplerSignatureInfo::signerSubjectDN() const +QString PopplerSignatureInfo::subjectDN() const { return m_info->signerSubjectDN(); } -QString PopplerSignatureInfo::location() const -{ - return m_info->location(); -} - -QString PopplerSignatureInfo::reason() const -{ - return m_info->reason(); -} - QDateTime PopplerSignatureInfo::signingTime() const { return QDateTime::fromTime_t( m_info->signingTime() ); } QByteArray PopplerSignatureInfo::signature() const { return m_info->signature(); } QList PopplerSignatureInfo::signedRangeBounds() const { return m_info->signedRangeBounds(); } bool PopplerSignatureInfo::signsTotalDocument() const { return m_info->signsTotalDocument(); } +QString PopplerSignatureInfo::location() const +{ + return m_info->location(); +} + +QString PopplerSignatureInfo::reason() const +{ + return m_info->reason(); +} + Okular::CertificateInfo *PopplerSignatureInfo::certificateInfo() const { return ( new PopplerCertificateInfo( m_info->certificateInfo() ) ); } diff --git a/generators/poppler/pdfsignatureutils.h b/generators/poppler/pdfsignatureutils.h index 2e19b6dfc..33959b391 100644 --- a/generators/poppler/pdfsignatureutils.h +++ b/generators/poppler/pdfsignatureutils.h @@ -1,64 +1,63 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef _OKULAR_GENERATOR_PDF_SIGNATUREINFO_H_ #define _OKULAR_GENERATOR_PDF_SIGNATUREINFO_H_ #include #include "core/signatureutils.h" class PopplerCertificateInfo : public Okular::CertificateInfo { public: PopplerCertificateInfo(const Poppler::CertificateInfo &info); ~PopplerCertificateInfo(); - bool isNull() const override; - int version() const override; + QByteArray version() const override; + QString issuerName() const override; + QString issuerDN() const override; QByteArray serialNumber() const override; - QString issuerInfo(EntityInfoKey) const override; - QString subjectInfo(EntityInfoKey) const override; QDateTime validityStart() const override; QDateTime validityEnd() const override; - KeyUsageExtensions keyUsageExtensions() const override; + KeyUsages keyUsages() const override; QByteArray publicKey() const override; PublicKeyType publicKeyType() const override; int publicKeyStrength() const override; bool isSelfSigned() const override; QByteArray certificateData() const override; private: Poppler::CertificateInfo *m_info; }; class PopplerSignatureInfo : public Okular::SignatureInfo { public: PopplerSignatureInfo( const Poppler::SignatureValidationInfo &info ); ~PopplerSignatureInfo(); SignatureStatus signatureStatus() const override; CertificateStatus certificateStatus() const override; - QString signerName() const override; - QString signerSubjectDN() const override; - QString location() const override; - QString reason() const override; + QString subjectName() const override; + QString subjectDN() const override; HashAlgorithm hashAlgorithm() const override; QDateTime signingTime() const override; QByteArray signature() const override; QList signedRangeBounds() const override; bool signsTotalDocument() const override; + QString location() const override; + QString reason() const override; Okular::CertificateInfo *certificateInfo() const override; private: Poppler::SignatureValidationInfo *m_info; }; #endif diff --git a/ui/signaturemodel.cpp b/ui/signaturemodel.cpp index c0a36c95a..345770652 100644 --- a/ui/signaturemodel.cpp +++ b/ui/signaturemodel.cpp @@ -1,323 +1,334 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan #include #include #include #include "core/annotations.h" #include "core/document.h" #include "core/observer.h" #include "core/page.h" #include "core/form.h" #include "core/signatureutils.h" #include "guiutils.h" static QVector getSignatureFormFields( Okular::Page* page ) { QVector signatureFormFields; foreach ( Okular::FormField *f, page->formFields() ) { if ( f->type() == Okular::FormField::FormSignature ) { signatureFormFields.append( static_cast( f ) ); } } return signatureFormFields; } struct SignatureItem { enum ItemData { RevisionInfo, SignatureValidity, SigningTime, Reason, FieldInfo, Other }; SignatureItem(); SignatureItem( SignatureItem *parent, Okular::FormFieldSignature *form, ItemData data, int page , int _pos ); //SignatureItem( SignatureItem *parent, int page, int pos ); ~SignatureItem(); SignatureItem *parent; QVector children; Okular::FormFieldSignature *signatureForm; QString displayString; ItemData itemData; int page; int pos; }; SignatureItem::SignatureItem() : parent( nullptr ), signatureForm( nullptr ), itemData( Other ), page( -1 ), pos( -1 ) { } SignatureItem::SignatureItem(SignatureItem *_parent, Okular::FormFieldSignature *form, ItemData data , int _page, int _pos ) : parent( _parent ), signatureForm( form ), itemData( data ), page( _page ), pos( _pos ) { Q_ASSERT( parent ); parent->children.append( this ); Okular::SignatureInfo *info = form->validate(); switch ( itemData ) { case RevisionInfo: - displayString = i18n("Rev. %1: Signed By %2", pos, info->signerName() ); + displayString = i18n("Rev. %1: Signed By %2", pos, info->subjectName() ); break; case SignatureValidity: displayString = GuiUtils::getReadableSigState( info->signatureStatus() ); break; case SigningTime: displayString = i18n("Signing Time: %1", info->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ); break; case Reason: { const QString reason = info->reason(); displayString = i18n("Reason: %1", !reason.isEmpty() ? reason : i18n("Not Available") ); break; } case FieldInfo: displayString = i18n("Field: %1 on page %2", form->name(), page+1 ); break; case Other: break; } } /*SignatureItem::SignatureItem( SignatureItem *_parent, int _page, int _pos ) : parent( _parent ), signatureForm( nullptr ), page( _page ), pos( _pos ) { Q_ASSERT( !parent->parent ); parent->children.append( this ); displayString = "pradhan"; }*/ SignatureItem::~SignatureItem() { qDeleteAll( children ); } class SignatureModelPrivate : public Okular::DocumentObserver { public: SignatureModelPrivate( SignatureModel *qq ); ~SignatureModelPrivate() override; void notifySetup( const QVector< Okular::Page * > &pages, int setupFlags ) override; QModelIndex indexForItem( SignatureItem *item ) const; void rebuildTree( const QVector< Okular::Page * > &pages ); SignatureItem* findItem( int page, int *index ) const; SignatureModel *q; SignatureItem *root; QPointer document; }; SignatureModelPrivate::SignatureModelPrivate( SignatureModel *qq ) : q( qq ), root( new SignatureItem ) { } SignatureModelPrivate::~SignatureModelPrivate() { delete root; } static void updateFormFieldSignaturePointer( SignatureItem *item, const QVector &pages ) { if ( item->signatureForm ) { foreach ( Okular::FormField *f, pages[item->page]->formFields() ) { if ( item->signatureForm->id() == f->id() ) { item->signatureForm = static_cast( f ); break; } } if ( !item->signatureForm ) qWarning() << "Lost signature form field, something went wrong"; } foreach ( SignatureItem *child, item->children ) updateFormFieldSignaturePointer( child, pages ); } void SignatureModelPrivate::notifySetup( const QVector &pages, int setupFlags ) { if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) ) { if ( setupFlags & Okular::DocumentObserver::UrlChanged ) { updateFormFieldSignaturePointer( root, pages ); } return; } q->beginResetModel(); qDeleteAll( root->children ); root->children.clear(); rebuildTree( pages ); q->endResetModel(); } QModelIndex SignatureModelPrivate::indexForItem( SignatureItem *item ) const { if ( item->parent ) { int index = item->parent->children.indexOf( item ); if ( index >= 0 && index < item->parent->children.count() ) return q->createIndex( index, 0, item ); } return QModelIndex(); } void SignatureModelPrivate::rebuildTree( const QVector< Okular::Page*> &pages ) { if ( pages.isEmpty() ) return; emit q->layoutAboutToBeChanged(); for ( int i = 0; i < pages.count(); i++ ) { QVector signatureFormFields = getSignatureFormFields( pages.at( i ) ); if ( signatureFormFields.isEmpty() ) continue; int pos = 1; foreach ( auto sf, signatureFormFields ) { SignatureItem *sigItem = new SignatureItem( root, sf, SignatureItem::RevisionInfo, i, pos ); new SignatureItem( sigItem, sf, SignatureItem::SignatureValidity, i, pos ); new SignatureItem( sigItem, sf, SignatureItem::SigningTime, i, pos ); new SignatureItem( sigItem, sf, SignatureItem::Reason, i, pos ); new SignatureItem( sigItem, sf, SignatureItem::FieldInfo, i, pos ); pos++; } } emit q->layoutChanged(); } SignatureItem *SignatureModelPrivate::findItem( int page, int *index ) const { for ( int i = 0; i < root->children.count(); i++ ) { SignatureItem *tmp = root->children.at( i ); if ( tmp->page == page ) { if ( index ) *index = i; return tmp; } } if ( index ) *index = -1; return nullptr; } SignatureModel::SignatureModel( Okular::Document *doc, QObject *parent ) : QAbstractItemModel( parent ), d_ptr( new SignatureModelPrivate( this ) ) { Q_D( SignatureModel ); d->document = doc; d->document->addObserver( d ); } SignatureModel::~SignatureModel() { Q_D( SignatureModel ); if ( d->document ) d->document->removeObserver( d ); } int SignatureModel::columnCount( const QModelIndex & ) const { return 1; } QVariant SignatureModel::data( const QModelIndex &index, int role ) const { if ( !index.isValid() ) return QVariant(); SignatureItem *item = static_cast( index.internalPointer() ); if ( item->signatureForm ) { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return item->displayString; case Qt::DecorationRole: if ( item->itemData == SignatureItem::RevisionInfo ) - return QIcon::fromTheme( QStringLiteral("dialog-yes") ); + return QIcon::fromTheme( QStringLiteral("application-pkcs7-signature") ); return QIcon(); case FormRole: if ( item->itemData == SignatureItem::RevisionInfo ) return item->signatureForm->id(); return -1; case PageRole: return item->page; } } return QVariant(); } bool SignatureModel::hasChildren( const QModelIndex &parent ) const { if ( !parent.isValid() ) return true; SignatureItem *item = static_cast( parent.internalPointer() ); return !item->children.isEmpty(); } +QVariant SignatureModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation != Qt::Horizontal ) + return QVariant(); + + if ( section == 0 && role == Qt::DisplayRole ) + return QString::fromLocal8Bit("Signatures"); + + return QVariant(); +} + QModelIndex SignatureModel::index( int row, int column, const QModelIndex &parent ) const { Q_D( const SignatureModel ); if ( row < 0 || column != 0 ) return QModelIndex(); SignatureItem *item = parent.isValid() ? static_cast( parent.internalPointer() ) : d->root; if ( row < item->children.count() ) return createIndex( row, column, item->children.at( row ) ); return QModelIndex(); } QModelIndex SignatureModel::parent( const QModelIndex &index ) const { Q_D( const SignatureModel ); if ( !index.isValid() ) return QModelIndex(); SignatureItem *item = static_cast( index.internalPointer() ); return d->indexForItem( item->parent ); } int SignatureModel::rowCount( const QModelIndex &parent ) const { Q_D( const SignatureModel ); SignatureItem *item = parent.isValid() ? static_cast( parent.internalPointer() ) : d->root; return item->children.count(); } #include "moc_signaturemodel.cpp" diff --git a/ui/signaturemodel.h b/ui/signaturemodel.h index f5575cb0a..45d99af4d 100644 --- a/ui/signaturemodel.h +++ b/ui/signaturemodel.h @@ -1,52 +1,53 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan namespace Okular { class Document; class FormFieldSignature; class SignatureInfo; } class SignatureModelPrivate; class SignatureModel : public QAbstractItemModel { Q_OBJECT public: enum { FormRole = Qt::UserRole + 1000, PageRole }; explicit SignatureModel( Okular::Document *doc, QObject *parent = nullptr ); virtual ~SignatureModel(); int columnCount( const QModelIndex &parent = QModelIndex() ) const override; QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; bool hasChildren( const QModelIndex &parent = QModelIndex() ) const override; + QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const override; QModelIndex parent( const QModelIndex &index ) const override; int rowCount( const QModelIndex &parent = QModelIndex() ) const override; Okular::FormFieldSignature* formFieldSignatureForIndex( const QModelIndex &index ) const; private: Q_DECLARE_PRIVATE( SignatureModel ) QScopedPointer d_ptr; }; #endif diff --git a/ui/signaturewidgets.cpp b/ui/signaturewidgets.cpp index 0557930ab..94696ccb7 100644 --- a/ui/signaturewidgets.cpp +++ b/ui/signaturewidgets.cpp @@ -1,286 +1,387 @@ -/*************************************************************************** +/*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "signaturewidgets.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/form.h" #include "core/page.h" #include "core/document.h" #include "core/sourcereference.h" #include "core/form.h" #include "settings.h" #include "guiutils.h" CertificateViewerModel::CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent ) : QAbstractTableModel( parent ) { - m_sigProperties.append( qMakePair( i18n("Subject Name"), sigInfo->signerName() ) ); - m_sigProperties.append( qMakePair( i18n("Subject Distinguished Name"), sigInfo->signerSubjectDN() ) ); + m_sigProperties.append( qMakePair( i18n("Subject Name"), sigInfo->subjectName() ) ); + m_sigProperties.append( qMakePair( i18n("Subject Distinguished Name"), sigInfo->subjectDN() ) ); m_sigProperties.append( qMakePair( i18n("Signing Time"), sigInfo->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); m_sigProperties.append( qMakePair( i18n("Hash Algorithm"), GuiUtils::getReadableHashAlgorithm( sigInfo->hashAlgorithm() ) ) ); m_sigProperties.append( qMakePair( i18n("Signature Status"), GuiUtils::getReadableSigState( sigInfo->signatureStatus() ) ) ); m_sigProperties.append( qMakePair( i18n("Certificate Status"), GuiUtils::getReadableCertState( sigInfo->certificateStatus() ) ) ); m_sigProperties.append( qMakePair( i18n("Signature Data"), QString::fromUtf8( sigInfo->signature().toHex(' ') ) ) ); m_sigProperties.append( qMakePair( i18n("Location"), QString( sigInfo->location() ) ) ); m_sigProperties.append( qMakePair( i18n("Reason"), QString( sigInfo->reason() ) ) ); m_sigProperties.append( qMakePair( QStringLiteral("----------"), QString("------Certificate Properties--------") ) ); Okular::CertificateInfo *certInfo = sigInfo->certificateInfo(); - m_sigProperties.append( qMakePair( i18n("Version"), QString("V" + QString::number(certInfo->version()) ) ) ); - m_sigProperties.append( qMakePair( i18n("Issuer Name"), certInfo->issuerInfo(Okular::CertificateInfo::CommonName) ) ); - m_sigProperties.append( qMakePair( i18n("Issuer Distinguished Name"), certInfo->issuerInfo(Okular::CertificateInfo::DistinguishedName) ) ); - m_sigProperties.append( qMakePair( i18n("Serial Number"), certInfo->serialNumber().toHex(' ') ) ); + m_sigProperties.append( qMakePair( i18n("Version"), certInfo->version() ) ); + m_sigProperties.append( qMakePair( i18n("Issuer Name"), certInfo->issuerName() ) ); + m_sigProperties.append( qMakePair( i18n("Issuer Distinguished Name"), certInfo->issuerDN() ) ); + m_sigProperties.append( qMakePair( i18n("Serial Number"), certInfo->serialNumber() ) ); m_sigProperties.append( qMakePair( i18n("Validity Start"), certInfo->validityStart().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); m_sigProperties.append( qMakePair( i18n("Validity End"), certInfo->validityEnd().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); - m_sigProperties.append( qMakePair( i18n("Public Key"), certInfo->publicKey().toHex(' ') ) ); + m_sigProperties.append( qMakePair( i18n("Public Key"), certInfo->publicKey() ) ); m_sigProperties.append( qMakePair( i18n("Is Self Signed"), certInfo->isSelfSigned() ? QString("true") : QString("false") ) ); } int CertificateViewerModel::columnCount( const QModelIndex & ) const { return 2; } int CertificateViewerModel::rowCount( const QModelIndex & ) const { return m_sigProperties.size(); } QVariant CertificateViewerModel::data( const QModelIndex &index, int role ) const { int row = index.row(); if ( !index.isValid() || row < 0 || row >= m_sigProperties.count() ) return QVariant(); switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: switch ( index.column() ) { case 0: return m_sigProperties[row].first; case 1: return m_sigProperties[row].second; default: return QString(); } case PropertyValueRole: return m_sigProperties[row].second; } return QVariant(); } QVariant CertificateViewerModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( role == Qt::TextAlignmentRole ) return QVariant( Qt::AlignLeft ); if ( orientation != Qt::Horizontal || role != Qt::DisplayRole) return QVariant(); switch ( section ) { case 0: return i18n("Property"); case 1: return i18n("Value"); default: return QVariant(); } } CertificateViewer::CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ) : QDialog( parent ), m_sigInfo( sigInfo ) { setModal( true ); setFixedSize( QSize( 450, 500 )); setWindowTitle( i18n("Signature Properties") ); auto sigPropLabel = new QLabel( this ); sigPropLabel->setText( i18n("Signature Properties:") ); auto sigPropTree = new QTreeView( this ); sigPropTree->setIndentation( 0 ); m_sigPropModel = new CertificateViewerModel( m_sigInfo, this ); sigPropTree->setModel( m_sigPropModel ); connect( sigPropTree, &QTreeView::clicked, this, &CertificateViewer::updateText ); m_sigPropText = new QTextEdit( this ); m_sigPropText->setReadOnly( true ); auto btnBox = new QDialogButtonBox( QDialogButtonBox::Close, this ); btnBox->button( QDialogButtonBox::Close )->setDefault( true ); connect( btnBox, &QDialogButtonBox::rejected, this, &SignaturePropertiesDialog::reject ); auto mainLayout = new QVBoxLayout( this ); mainLayout->addWidget( sigPropLabel ); mainLayout->addWidget( sigPropTree ); mainLayout->addWidget( m_sigPropText ); mainLayout->addWidget( btnBox ); setLayout( mainLayout ); } void CertificateViewer::updateText( const QModelIndex &index ) { m_sigPropText->setText( m_sigPropModel->data( index, CertificateViewerModel::PropertyValueRole ).toString() ); } SignaturePropertiesDialog::SignaturePropertiesDialog( Okular::Document *doc, Okular::FormFieldSignature *form, QWidget *parent ) : QDialog( parent ), m_doc( doc ), m_signatureForm( form ) { setModal( true ); setWindowTitle( i18n("Signature Properties") ); m_signatureInfo = m_signatureForm->validate(); auto mainLayout = new QVBoxLayout; // signature validation status auto sigStatusBox = new QGroupBox( i18n("Validity Status") ); auto hBoxLayout = new QHBoxLayout; auto pixmapLabel = new QLabel; pixmapLabel->setPixmap( KIconLoader::global()->loadIcon( QLatin1String("application-certificate"), KIconLoader::Desktop, KIconLoader::SizeSmallMedium ) ); hBoxLayout->addWidget( pixmapLabel ); auto sigStatusFormLayout = new QFormLayout; const Okular::SignatureInfo::SignatureStatus sigStatus = m_signatureInfo->signatureStatus(); sigStatusFormLayout->addRow( i18n("Signature Validity:"), new QLabel( GuiUtils::getReadableSigState( sigStatus ) ) ); QString modString; if ( sigStatus == Okular::SignatureInfo::SignatureValid ) { if ( m_signatureInfo->signsTotalDocument() ) { modString = i18n("The document has not been modified since it was signed."); } else { modString = i18n("The revision of the document that was covered by this signature has not been modified;\n" "however there have been subsequent changes to the document."); } } else if ( sigStatus == Okular::SignatureInfo::SignatureDigestMismatch ) { modString = i18n("The document has been modified in a way not permitted by a previous signer."); } else { modString = i18n("The document integrity verification could not be completed."); } sigStatusFormLayout->addRow( i18n("Document Modifications:"), new QLabel( modString ) ); hBoxLayout->addLayout( sigStatusFormLayout ); sigStatusBox->setLayout( hBoxLayout ); mainLayout->addWidget( sigStatusBox ); // additional information auto extraInfoBox = new QGroupBox( i18n("Additional Information") ); auto extraInfoFormLayout = new QFormLayout; - extraInfoFormLayout->addRow( i18n("Signed By:"), new QLabel( m_signatureInfo->signerName() ) ); + extraInfoFormLayout->addRow( i18n("Signed By:"), new QLabel( m_signatureInfo->subjectName() ) ); extraInfoFormLayout->addRow( i18n("Signing Time:"), new QLabel( m_signatureInfo->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); auto getValidString = [=]( const QString &str ) -> QString { return !str.isEmpty() ? str : i18n("Not Available"); }; // optional info extraInfoFormLayout->addRow( i18n("Reason:"), new QLabel( getValidString( m_signatureInfo->reason() ) ) ); extraInfoFormLayout->addRow( i18n("Location:"), new QLabel( getValidString( m_signatureInfo->location() ) ) ); extraInfoBox->setLayout( extraInfoFormLayout ); mainLayout->addWidget( extraInfoBox ); // document version auto revisionBox = new QGroupBox( i18n("Document Version") ); auto revisionLayout = new QHBoxLayout; QVector signatureFormFields = GuiUtils::getSignatureFormFields( m_doc ); revisionLayout->addWidget( new QLabel( i18nc("Document Revision of ", "Document Revision %1 of %2", signatureFormFields.indexOf( m_signatureForm ) + 1, signatureFormFields.size() ) ) ); revisionLayout->addStretch(); auto revisionBtn = new QPushButton( i18n( "View Signed Version...") ); revisionBtn->setEnabled( !m_signatureInfo->signsTotalDocument() ); connect( revisionBtn, &QPushButton::clicked, this, &SignaturePropertiesDialog::viewSignedVersion ); revisionLayout->addWidget( revisionBtn ); revisionBox->setLayout( revisionLayout ); mainLayout->addWidget( revisionBox ); // button box auto btnBox = new QDialogButtonBox( QDialogButtonBox::Close, this ); auto certPropBtn = new QPushButton( i18n( "Vew Certificate..."), this ); - certPropBtn->setVisible(m_signatureInfo->certificateInfo()->isNull()); btnBox->button( QDialogButtonBox::Close )->setDefault( true ); btnBox->addButton( certPropBtn, QDialogButtonBox::ActionRole ); connect( btnBox, &QDialogButtonBox::rejected, this, &SignaturePropertiesDialog::reject ); connect( certPropBtn, &QPushButton::clicked, this, &SignaturePropertiesDialog::viewCertificateProperties ); mainLayout->addWidget( btnBox ); setLayout( mainLayout ); resize( mainLayout->sizeHint() ); } void SignaturePropertiesDialog::viewCertificateProperties() { CertificateViewer sigPropDlg( m_signatureInfo, this ); sigPropDlg.exec(); } void SignaturePropertiesDialog::viewSignedVersion() { QByteArray data; m_doc->requestSignedRevisionData( m_signatureInfo, &data ); const QString tmpDir = QStandardPaths::writableLocation( QStandardPaths::TempLocation ); QTemporaryFile tf( tmpDir + "/revision_XXXXXX.pdf" ); if ( !tf.open() ) { KMessageBox::error( this, i18n("Could not open revision for preview" ) ); return; } tf.write(data); RevisionViewer view( tf.fileName(), this); view.exec(); tf.close(); } RevisionViewer::RevisionViewer( const QString &filename, QWidget *parent ) : FilePrinterPreview( filename, parent ) { setWindowTitle( i18n("Revision Preview") ); } RevisionViewer::~RevisionViewer() { } +TreeView1::TreeView1(Okular::Document *document, QWidget *parent) + : QTreeView( parent ), m_document( document ) +{ +} + +void TreeView1::paintEvent( QPaintEvent *event ) +{ + bool hasSignatures = false; + for ( uint i = 0; i < m_document->pages(); i++ ) + { + foreach (Okular::FormField *f, m_document->page( i )->formFields() ) + { + if ( f->type() == Okular::FormField::FormSignature ) + { + hasSignatures = true; + break; + } + } + } + + if ( !hasSignatures ) + { + QPainter p( viewport() ); + p.setRenderHint( QPainter::Antialiasing, true ); + p.setClipRect( event->rect() ); + + QTextDocument document; + document.setHtml( i18n( "
" + "This document does not contain any digital signature." + "
" ) ); + document.setTextWidth( width() - 50 ); + + const uint w = document.size().width() + 20; + const uint h = document.size().height() + 20; + p.setBrush( palette().background() ); + p.translate( 0.5, 0.5 ); + p.drawRoundRect( 15, 15, w, h, (8*200)/w, (8*200)/h ); + + p.translate( 20, 20 ); + document.drawContents( &p ); + + } + else + { + QTreeView::paintEvent( event ); + } +} + +SignaturePanel::SignaturePanel( QWidget *parent, Okular::Document *document ) + : QWidget( parent ), m_document( document ) +{ + auto vLayout = new QVBoxLayout( this ); + vLayout->setMargin( 0 ); + vLayout->setSpacing( 6 ); + + m_view = new TreeView1( m_document, this ); + m_view->setAlternatingRowColors( true ); + m_view->setSelectionMode( QAbstractItemView::ExtendedSelection ); + m_view->header()->hide(); + + m_model = new SignatureModel( m_document, this ); + + m_view->setModel( m_model ); + connect(m_view, &TreeView1::activated, this, &SignaturePanel::activated); + + vLayout->addWidget( m_view ); +} + +void SignaturePanel::activated( const QModelIndex &index ) +{ + int formId = m_model->data( index, SignatureModel::FormRole ).toInt(); + if ( formId == -1 ) + return; + + auto formFields = GuiUtils::getSignatureFormFields( m_document ); + Okular::FormFieldSignature *sf; + foreach( auto f, formFields ) + { + if ( f->id() == formId ) + { + sf = f; + break; + } + } + if ( !sf ) + return; + + Okular::NormalizedRect nr = sf->rect(); + Okular::DocumentViewport vp; + vp.pageNumber = m_model->data( index, SignatureModel::PageRole ).toInt(); + vp.rePos.enabled = true; + vp.rePos.pos = Okular::DocumentViewport::Center; + vp.rePos.normalizedX = ( nr.right + nr.left ) / 2.0; + vp.rePos.normalizedY = ( nr.bottom + nr.top ) / 2.0; + m_document->setViewport( vp, nullptr, true ); +} + +SignaturePanel::~SignaturePanel() +{ + m_document->removeObserver( this ); +} + #include "moc_signaturewidgets.cpp" diff --git a/ui/signaturewidgets.h b/ui/signaturewidgets.h index b2b683905..6e5ea9151 100644 --- a/ui/signaturewidgets.h +++ b/ui/signaturewidgets.h @@ -1,91 +1,122 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef OKULAR_SIGNATUREWIDGETS_H #define OKULAR_SIGNATUREWIDGETS_H #include #include #include #include #include "core/signatureutils.h" #include "core/observer.h" #include "fileprinterpreview.h" #include "signaturemodel.h" class QTextEdit; namespace Okular { class Document; class FormFieldSignature; class SignatureInfo; } class CertificateViewerModel : public QAbstractTableModel { Q_OBJECT public: explicit CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent = nullptr ); enum { PropertyValueRole = Qt::UserRole }; int columnCount( const QModelIndex &parent = QModelIndex() ) const override; int rowCount( const QModelIndex &parent = QModelIndex() ) const override; QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; private: QVector< QPair > m_sigProperties; }; class CertificateViewer : public QDialog { Q_OBJECT public: CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ); private Q_SLOTS: void updateText( const QModelIndex &index ); private: CertificateViewerModel *m_sigPropModel; QTextEdit *m_sigPropText; Okular::SignatureInfo *m_sigInfo; }; class SignaturePropertiesDialog : public QDialog { Q_OBJECT public: SignaturePropertiesDialog( Okular::Document *doc, Okular::FormFieldSignature *form, QWidget *parent ); private Q_SLOTS: void viewSignedVersion(); void viewCertificateProperties(); private: Okular::Document *m_doc; Okular::FormFieldSignature *m_signatureForm; Okular::SignatureInfo *m_signatureInfo; }; class RevisionViewer : public Okular::FilePrinterPreview { Q_OBJECT public: RevisionViewer( const QString &filename, QWidget *parent = nullptr ); ~RevisionViewer(); }; +class TreeView1 : public QTreeView +{ + Q_OBJECT + + public: + TreeView1( Okular::Document *document, QWidget *parent = Q_NULLPTR ); + protected: + void paintEvent( QPaintEvent *event ) override; + + private: + Okular::Document *m_document; +}; + +class SignaturePanel : public QWidget, public Okular::DocumentObserver +{ + Q_OBJECT + public: + SignaturePanel( QWidget * parent, Okular::Document * document ); + ~SignaturePanel(); + + //void notifySetup( const QVector< Okular::Page * > & pages, int setupFlags ) override; + private Q_SLOTS: + void activated( const QModelIndex& ); + + private: + Okular::Document *m_document; + TreeView1 *m_view; + SignatureModel *m_model; +}; + + #endif