From a7a80bd5cb2d7afa2f7c7beae882aee0e083c41c Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Fri, 15 Sep 2023 13:34:16 +0300 Subject: [PATCH] Handle ASiC-S XAdES signatures (#1203) IB-7593 Signed-off-by: Raul Metsma --- client/DigiDoc.cpp | 27 +++++++++++++++++---------- client/DigiDoc.h | 1 + client/common_enums.h | 1 + client/dialogs/FileDialog.cpp | 25 +++++++++++-------------- client/translations/en.ts | 4 ++++ client/translations/et.ts | 4 ++++ client/translations/ru.ts | 4 ++++ client/widgets/ContainerPage.cpp | 2 ++ client/widgets/WarningItem.cpp | 7 +++++++ 9 files changed, 51 insertions(+), 24 deletions(-) diff --git a/client/DigiDoc.cpp b/client/DigiDoc.cpp index fa12b8d5b..1088d27d7 100644 --- a/client/DigiDoc.cpp +++ b/client/DigiDoc.cpp @@ -335,19 +335,17 @@ void SDocumentModel::open(int row) { if(row >= rowCount()) return; - QString path = FileDialog::tempPath(FileDialog::safeName(from(doc->b->dataFiles().at(size_t(row))->fileName()))); if(!verifyFile(path)) return; - QFileInfo f(save(row, path)); - if( !f.exists() ) + if(!QFileInfo::exists(save(row, path))) return; - doc->m_tempFiles.append(f.absoluteFilePath()); - FileDialog::setReadOnly(f.absoluteFilePath()); - if(!doc->fileName().endsWith(QStringLiteral(".pdf"), Qt::CaseInsensitive) && FileDialog::isSignedPDF(f.absoluteFilePath())) - qApp->showClient({ f.absoluteFilePath() }, false, false, true); + doc->m_tempFiles.append(path); + FileDialog::setReadOnly(path); + if(!doc->fileName().endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive) && FileDialog::isSignedPDF(path)) + qApp->showClient({ path }, false, false, true); else - QDesktopServices::openUrl(QUrl::fromLocalFile(f.absoluteFilePath())); + QDesktopServices::openUrl(QUrl::fromLocalFile(path)); } bool SDocumentModel::removeRow(int row) @@ -447,11 +445,20 @@ bool DigiDoc::isError(bool failure, const QString &msg) const return !b || failure; } +bool DigiDoc::isAsicS() const +{ + return b && b->mediaType() == "application/vnd.etsi.asic-s+zip" && + std::any_of(m_signatures.cbegin(), m_signatures.cend(), [](const DigiDocSignature &s) { + return s.profile().contains(QLatin1String("BES"), Qt::CaseInsensitive); + }); +} + bool DigiDoc::isPDF() const { return b && b->mediaType() == "application/pdf"; } bool DigiDoc::isModified() const { return modified; } + bool DigiDoc::isSupported() const { return b && b->mediaType() == "application/vnd.etsi.asic-e+zip"; @@ -493,8 +500,8 @@ bool DigiDoc::open( const QString &file ) dlg->addButton(WarningDialog::YES, ContainerSave); return dlg->exec() == ContainerSave; }; - if((file.endsWith(QStringLiteral(".pdf"), Qt::CaseInsensitive) || - file.endsWith(QStringLiteral(".ddoc"), Qt::CaseInsensitive)) && !serviceConfirmation()) + if((file.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive) || + file.endsWith(QLatin1String(".ddoc"), Qt::CaseInsensitive)) && !serviceConfirmation()) return false; try { diff --git a/client/DigiDoc.h b/client/DigiDoc.h index ea220eb8c..e9c72b8ad 100644 --- a/client/DigiDoc.h +++ b/client/DigiDoc.h @@ -126,6 +126,7 @@ class DigiDoc: public QObject void clear(); DocumentModel *documentModel() const; QString fileName() const; + bool isAsicS() const; bool isPDF() const; bool isModified() const; bool isSupported() const; diff --git a/client/common_enums.h b/client/common_enums.h index aab7c49a3..cf4078d3c 100644 --- a/client/common_enums.h +++ b/client/common_enums.h @@ -94,6 +94,7 @@ enum WarningType { InvalidTimestampWarning, UnknownSignatureWarning, UnknownTimestampWarning, + UnsupportedAsicSWarning, UnsupportedDDocWarning, EmptyFileWarning, }; diff --git a/client/dialogs/FileDialog.cpp b/client/dialogs/FileDialog.cpp index ff52cb828..bab6851e3 100644 --- a/client/dialogs/FileDialog.cpp +++ b/client/dialogs/FileDialog.cpp @@ -34,6 +34,7 @@ #ifdef Q_OS_WIN #include #include +#include template class CPtr @@ -125,19 +126,14 @@ int FileDialog::fileZone(const QString &path) bool FileDialog::isSignedPDF(const QString &path) { - const QFileInfo f(path); - if(f.suffix().compare(QStringLiteral("pdf"), Qt::CaseInsensitive)) + if(!path.endsWith(QLatin1String("pdf"), Qt::CaseInsensitive)) return false; QFile file(path); if(!file.open(QIODevice::ReadOnly)) return false; QByteArray blob = file.readAll(); - for(const QByteArray &token: {"adbe.pkcs7.detached", "adbe.pkcs7.sha1", "adbe.x509.rsa_sha1", "ETSI.CAdES.detached"}) - { - if(blob.indexOf(token) > 0) - return true; - } - return false; + static const auto list = {"adbe.pkcs7.detached", "adbe.pkcs7.sha1", "adbe.x509.rsa_sha1", "ETSI.CAdES.detached"}; + return std::any_of(list.begin(), list.end(), [&blob](const char *token) { return blob.indexOf(token) > 0; }); } void FileDialog::setFileZone(const QString &path, int zone) @@ -290,7 +286,7 @@ QString FileDialog::getSaveFileName( QWidget *parent, const QString &caption, QString FileDialog::normalized(const QString &data) { - static constexpr std::array list = {{ + static constexpr std::array list {{ {0xE2, 0x80, 0x8E}, // \u200E LEFT-TO-RIGHT MARK {0xE2, 0x80, 0x8F}, // \u200F RIGHT-TO-LEFT MARK {0xE2, 0x80, 0xAA}, // \u202A LEFT-TO-RIGHT EMBEDDING @@ -340,15 +336,16 @@ QString FileDialog::safeName(const QString &file) QString filename = info.fileName(); #if defined(Q_OS_WIN) static const QStringList disabled { "CON", "PRN", "AUX", "NUL", - "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", - "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; + "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", + "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; if(disabled.contains(info.baseName(), Qt::CaseInsensitive)) filename = QStringLiteral("___.") + info.suffix(); - filename.replace(QRegularExpression(QStringLiteral("[\\\\/*:?\"<>|]")), QStringLiteral("_")); + static const QRegularExpression replace(QStringLiteral("[\\\\/*:?\"<>|]")); #elif defined(Q_OS_MAC) - filename.replace(QRegularExpression(QStringLiteral("[\\\\/:]")), QStringLiteral("_")); + static const QRegularExpression replace(QStringLiteral("[\\\\/:]")); #else - filename.replace(QRegularExpression(QStringLiteral("[\\\\/]")), QStringLiteral("_")); + static const QRegularExpression replace(QStringLiteral("[\\\\/]")); #endif + filename.replace(replace, QStringLiteral("_")); return filename; } diff --git a/client/translations/en.ts b/client/translations/en.ts index e39837cd9..11563592c 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -3288,6 +3288,10 @@ Additional licenses and components Certificates expire soon! Certificates expire soon! + + This ASiC-S container contains XAdES signature. You are not allowed to add or remove signatures to this container. + This ASiC-S container contains XAdES signature. You are not allowed to add or remove signatures to this container. + WarningRibbon diff --git a/client/translations/et.ts b/client/translations/et.ts index 97781458f..98a9d3dc3 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -3288,6 +3288,10 @@ Täiendavad litsentsid ja komponendid Certificates have expired! Sertifikaadid on aegunud! + + This ASiC-S container contains XAdES signature. You are not allowed to add or remove signatures to this container. + Tegemist on XAdES allkirja sisalduva ASiC-S ümbrikuga. Sellele ümbrikule ei saa allkirja lisada ega eemaldada. + WarningRibbon diff --git a/client/translations/ru.ts b/client/translations/ru.ts index 8a75030b5..e2d739f7f 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -3293,6 +3293,10 @@ Additional licenses and components Certificates expire soon! Срок действия сертификатов скоро истекает! + + This ASiC-S container contains XAdES signature. You are not allowed to add or remove signatures to this container. + Речь идет о конверте ASiC-S, содержащемся в подписи XAdES. К данному контейнеру нельзя добавить или удалить из него подпись. + WarningRibbon diff --git a/client/widgets/ContainerPage.cpp b/client/widgets/ContainerPage.cpp index a01ef63c8..272c0aed9 100644 --- a/client/widgets/ContainerPage.cpp +++ b/client/widgets/ContainerPage.cpp @@ -332,6 +332,8 @@ void ContainerPage::transition(DigiDoc* container) emit warning(WarningText(i.key(), i.value())); if(container->fileName().endsWith(QStringLiteral("ddoc"), Qt::CaseInsensitive)) emit warning(UnsupportedDDocWarning); + if(container->isAsicS()) + emit warning(UnsupportedAsicSWarning); hasEmptyFile = false; for (auto i = 0; i < container->documentModel()->rowCount(); i++) diff --git a/client/widgets/WarningItem.cpp b/client/widgets/WarningItem.cpp index 1394f55ef..d59abce8e 100644 --- a/client/widgets/WarningItem.cpp +++ b/client/widgets/WarningItem.cpp @@ -134,6 +134,13 @@ void WarningItem::lookupWarning() warnText.details = tr("More information"); warnText.page = ria::qdigidoc4::SignDetails; break; + case ria::qdigidoc4::UnsupportedAsicSWarning: + warnText.text = tr("This ASiC-S container contains XAdES signature. " + "You are not allowed to add or remove signatures to this container."); + warnText.url = tr("https://www.id.ee/en/article/digidoc-container-format-life-cycle-2/"); + warnText.details = tr("More information"); + warnText.page = ria::qdigidoc4::SignDetails; + break; case ria::qdigidoc4::UnsupportedDDocWarning: warnText.text = tr("The current file is a DigiDoc container that is not supported officially any longer. You are not allowed to add or remove signatures to this container."); warnText.url = tr("https://www.id.ee/en/article/digidoc-container-format-life-cycle-2/");