From 20180ed5bbacb8f583576016dc2b1d39d068e2cd Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Tue, 31 May 2022 16:27:33 +0300 Subject: [PATCH] Add SID V2 support (#954) IB-6810 Signed-off-by: Raul Metsma --- client/Diagnostics.cpp | 2 ++ client/MainWindow.cpp | 2 +- client/dialogs/SmartIDProgress.cpp | 53 ++++++++++++++++++++++-------- client/dialogs/SmartIDProgress.h | 2 +- client/translations/en.ts | 4 +++ client/translations/et.ts | 4 +++ client/translations/ru.ts | 4 +++ 7 files changed, 56 insertions(+), 15 deletions(-) diff --git a/client/Diagnostics.cpp b/client/Diagnostics.cpp index a638703ae..40ec610f4 100644 --- a/client/Diagnostics.cpp +++ b/client/Diagnostics.cpp @@ -41,7 +41,9 @@ void Diagnostics::generalInfo(QTextStream &s) const #ifdef CONFIG_URL << "
CONFIG_URL: " << CONFIG_URL << "
SID-PROXY-URL: " << Configuration::instance().object().value(QStringLiteral("SID-PROXY-URL")).toString(QStringLiteral(SMARTID_URL)) + << "
SIDV2-PROXY-URL: " << Configuration::instance().object().value(QStringLiteral("SIDV2-PROXY-URL")).toString(QStringLiteral(SMARTID_URL)) << "
SID-SK-URL: " << Configuration::instance().object().value(QStringLiteral("SID-SK-URL")).toString(QStringLiteral(SMARTID_URL)) + << "
SIDV2-SK-URL: " << Configuration::instance().object().value(QStringLiteral("SIDV2-SK-URL")).toString(QStringLiteral(SMARTID_URL)) << "
MID-PROXY-URL: " << Configuration::instance().object().value(QStringLiteral("MID-PROXY-URL")).toString(QStringLiteral(MOBILEID_URL)) << "
MID-SK-URL: " << Configuration::instance().object().value(QStringLiteral("MID-SK-URL")).toString(QStringLiteral(MOBILEID_URL)) << "
RPUUID: " << (QSettings().value(QStringLiteral("MIDUUID-CUSTOM"), QSettings().contains(QStringLiteral("MIDUUID"))).toBool() ? tr("is set manually") : tr("is set by default")) diff --git a/client/MainWindow.cpp b/client/MainWindow.cpp index 74e029370..c9a428e64 100644 --- a/client/MainWindow.cpp +++ b/client/MainWindow.cpp @@ -469,7 +469,7 @@ void MainWindow::onSignAction(int action, const QString &info1, const QString &i case SignatureSmartID: sign([this, info1, info2](const QString &city, const QString &state, const QString &zip, const QString &country, const QString &role) { SmartIDProgress s(this); - return s.init(info1, info2) && + return s.init(info1, info2, digiDoc->fileName()) && digiDoc->sign(city, state, zip, country, role, &s); }); break; diff --git a/client/dialogs/SmartIDProgress.cpp b/client/dialogs/SmartIDProgress.cpp index 7b5753218..9448a794b 100644 --- a/client/dialogs/SmartIDProgress.cpp +++ b/client/dialogs/SmartIDProgress.cpp @@ -61,13 +61,14 @@ class SmartIDProgress::Private final: public QDialog, public Ui::MobileProgress QTimeLine *statusTimer = nullptr; QNetworkAccessManager *manager = nullptr; QNetworkRequest req; - QString documentNumber, sessionID; + QString documentNumber, sessionID, fileName; X509Cert cert; std::vector signature; QEventLoop l; #ifdef CONFIG_URL - QString PROXYURL = Configuration::instance().object().value(QStringLiteral("SID-PROXY-URL")).toString(QStringLiteral(SMARTID_URL)); - QString SKURL = Configuration::instance().object().value(QStringLiteral("SID-SK-URL")).toString(QStringLiteral(SMARTID_URL)); + QJsonObject config = Configuration::instance().object(); + QString PROXYURL = config.value(QStringLiteral("SIDV2-PROXY-URL")).toString(config.value(QStringLiteral("SID-PROXY-URL")).toString(QStringLiteral(SMARTID_URL))); + QString SKURL = config.value(QStringLiteral("SIDV2-SK-URL")).toString(config.value(QStringLiteral("SID-SK-URL")).toString(QStringLiteral(SMARTID_URL))); #else QString PROXYURL = QSettings().value(QStringLiteral("SID-PROXY-URL"), QStringLiteral(SMARTID_URL)).toString(); QString SKURL = QSettings().value(QStringLiteral("SID-SK-URL"), QStringLiteral(SMARTID_URL)).toString(); @@ -87,7 +88,7 @@ SmartIDProgress::SmartIDProgress(QWidget *parent) : d(new Private(parent)) { const_cast(SIDLog()).setEnabled(QtDebugMsg, - true || QFile::exists(QStringLiteral("%1/%2.log").arg(QDir::tempPath(), qApp->applicationName()))); + QFile::exists(QStringLiteral("%1/%2.log").arg(QDir::tempPath(), qApp->applicationName()))); d->setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint); d->setupUi(d); d->move(parent->geometry().center() - d->geometry().center()); @@ -131,7 +132,7 @@ background-color: #007aff; QList trusted; #ifdef CONFIG_URL ssl.setCaCertificates({}); - for(const QJsonValue cert: Configuration::instance().object().value(QStringLiteral("CERT-BUNDLE")).toArray()) + for(const QJsonValue cert: d->config.value(QStringLiteral("CERT-BUNDLE")).toArray()) trusted << QSslCertificate(QByteArray::fromBase64(cert.toString().toLatin1()), QSsl::Der); #endif d->req.setSslConfiguration(ssl); @@ -247,10 +248,17 @@ background-color: #007aff; else if(result.value(QStringLiteral("state")).toString() != QStringLiteral("RUNNING")) { QString endResult = result.value(QStringLiteral("result")).toObject().value(QStringLiteral("endResult")).toString(); - if(endResult == QStringLiteral("USER_REFUSED")) + if(endResult == QStringLiteral("USER_REFUSED") || + endResult == QStringLiteral("USER_REFUSED_CERT_CHOICE") || + endResult == QStringLiteral("USER_REFUSED_DISPLAYTEXTANDPIN") || + endResult == QStringLiteral("USER_REFUSED_VC_CHOICE") || + endResult == QStringLiteral("USER_REFUSED_CONFIRMATIONMESSAGE") || + endResult == QStringLiteral("USER_REFUSED_CONFIRMATIONMESSAGE_WITH_VC_CHOICE")) returnError(tr("User denied or cancelled")); else if(endResult == QStringLiteral("TIMEOUT")) returnError(tr("Failed to sign container. Your Smart-ID transaction has expired or user account not found.")); + else if(endResult == QStringLiteral("REQUIRED_INTERACTION_NOT_SUPPORTED_BY_APP")) + returnError(tr("Failed to sign container. You need to update your Smart-ID application to sign documents in DigiDoc4 Client.")); else if(endResult == QStringLiteral("WRONG_VC")) returnError(tr("Error: an incorrect control code was chosen")); else if(endResult == QStringLiteral("DOCUMENT_UNUSABLE")) @@ -297,13 +305,19 @@ X509Cert SmartIDProgress::cert() const return d->cert; } -bool SmartIDProgress::init(const QString &country, const QString &idCode) +bool SmartIDProgress::init(const QString &country, const QString &idCode, const QString &fileName) { if(!d->UUID.isEmpty() && QUuid(d->UUID).isNull()) { WarningDialog(tr("Failed to send request. Check your %1 service access settings.").arg(tr("Smart-ID")), {}, d->parentWidget()).exec(); return false; } + QFileInfo info(fileName); + QString displayFile = info.completeBaseName(); + if(displayFile.size() > 6) + displayFile = displayFile.left(3) + QStringLiteral("...") + displayFile.right(3); + displayFile += QStringLiteral(".") + info.suffix(); + d->fileName = displayFile; d->sessionID.clear(); QByteArray data = QJsonDocument({ {"relyingPartyUUID", d->UUID.isEmpty() ? QStringLiteral("00000000-0000-0000-0000-000000000000") : d->UUID}, @@ -311,7 +325,11 @@ bool SmartIDProgress::init(const QString &country, const QString &idCode) {"certificateLevel", "QUALIFIED"}, {"nonce", QUuid::createUuid().toString().remove('-').mid(1, 30)} }).toJson(); - d->req.setUrl(QUrl(QStringLiteral("%1/certificatechoice/pno/%2/%3").arg(d->URL(), country, idCode))); + if (d->req.url().path().contains(QStringLiteral("v1"), Qt::CaseInsensitive)) { + d->req.setUrl(QUrl(QStringLiteral("%1/certificatechoice/pno/%2/%3").arg(d->URL(), country, idCode))); + } else { + d->req.setUrl(QUrl(QStringLiteral("%1/certificatechoice/etsi/PNO%2-%3").arg(d->URL(), country, idCode))); + } qCDebug(SIDLog).noquote() << d->req.url() << data; d->manager->post(d->req, data); d->info->setText(tr("Open the Smart-ID application on your smart device and confirm device for signing.")); @@ -344,17 +362,26 @@ std::vector SmartIDProgress::sign(const std::string &method, cons "and enter Smart-ID PIN2-code.")); d->code->setAccessibleName(QStringLiteral("%1 %2. %3").arg(d->controlCode->text(), d->code->text(), d->info->text())); - QByteArray data = QJsonDocument({ + QJsonObject req{ {"relyingPartyUUID", (d->UUID.isEmpty() ? QStringLiteral("00000000-0000-0000-0000-000000000000") : d->UUID)}, {"relyingPartyName", d->NAME}, {"certificateLevel", "QUALIFIED"}, {"hash", QString(QByteArray::fromRawData((const char*)digest.data(), int(digest.size())).toBase64())}, {"hashType", digestMethod}, - {"requestProperties", QJsonObject{{"vcChoice", true}}}, - {"displayText", "%1"} - }).toJson(); + }; + QString escape = tr("Sign document"); + if (d->req.url().path().contains(QStringLiteral("v1"), Qt::CaseInsensitive)) { + req[QStringLiteral("requestProperties")] = QJsonObject{{"vcChoice", true}}; + req[QStringLiteral("displayText")] = "%1"; + } else { + req[QStringLiteral("allowedInteractionsOrder")] = QJsonArray{QJsonObject{ + {"type", "confirmationMessageAndVerificationCodeChoice"}, + {"displayText200", "%1"} + }}; + escape = QStringLiteral("%1 %2").arg(tr("Sign document"), d->fileName); + } // Workaround SID proxy issues - data = QString::fromUtf8(data).arg(escapeUnicode(tr("Sign document"))).toUtf8(); + QByteArray data = QString::fromUtf8(QJsonDocument(req).toJson()).arg(escapeUnicode(escape)).toUtf8(); d->req.setUrl(QUrl(QStringLiteral("%1/signature/document/%2").arg(d->URL(), d->documentNumber))); qCDebug(SIDLog).noquote() << d->req.url() << data; d->manager->post(d->req, data); diff --git a/client/dialogs/SmartIDProgress.h b/client/dialogs/SmartIDProgress.h index 6847b3834..4c8c6f691 100644 --- a/client/dialogs/SmartIDProgress.h +++ b/client/dialogs/SmartIDProgress.h @@ -32,7 +32,7 @@ class SmartIDProgress final: public digidoc::Signer explicit SmartIDProgress(QWidget *parent = nullptr); ~SmartIDProgress() final; digidoc::X509Cert cert() const final; - bool init(const QString &country, const QString &idCode); + bool init(const QString &country, const QString &idCode, const QString &fileName); std::vector sign(const std::string &method, const std::vector &digest) const final; private: diff --git a/client/translations/en.ts b/client/translations/en.ts index 63a1c9e07..21caad3e5 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -1929,6 +1929,10 @@ and enter Smart-ID PIN2-code. Failed to sign container. Your Smart-ID transaction has expired or user account not found. Failed to sign container. Your Smart-ID transaction has expired or user account not found. + + Failed to sign container. You need to update your Smart-ID application to sign documents in DigiDoc4 Client. + Failed to sign container. You need to update your Smart-ID application to sign documents in DigiDoc4 Client. + NoCardInfo diff --git a/client/translations/et.ts b/client/translations/et.ts index ed64bb1ad..a23f23a11 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -1929,6 +1929,10 @@ ja sisesta nutiseadmes Smart-ID PIN2-kood. Failed to sign container. Your Smart-ID transaction has expired or user account not found. Ümbriku allkirjastamine ebaõnnestus. Sinu Smart-ID toiming aegus või kontot ei leitud. + + Failed to sign container. You need to update your Smart-ID application to sign documents in DigiDoc4 Client. + Ümbriku allkirjastamine ebaõnnestus. DigiDoc4 kliendis allkirjastamiseks pead Smart-ID rakendust uuendama. + NoCardInfo diff --git a/client/translations/ru.ts b/client/translations/ru.ts index 6c9962da2..8030a2ee0 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -1932,6 +1932,10 @@ and enter Smart-ID PIN2-code. Failed to sign container. Your Smart-ID transaction has expired or user account not found. Не удалось подписать контейнер. Срок действия вашей операции Smart-ID истек или учетная запись не найдена. + + Failed to sign container. You need to update your Smart-ID application to sign documents in DigiDoc4 Client. + Не удалось подписать контейнер. Для подписания с помощью Smart-ID в программе DigiDoc4 клиент нужно обновить приложение Smart-ID. + NoCardInfo