From bfa1dddb298c3d746e91f297c0c8ea8ba41a8fba Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Mon, 25 Nov 2024 11:12:27 +0200 Subject: [PATCH] Update to new UI Signed-off-by: Raul Metsma --- client/CDoc2.cpp | 14 +++-- client/CryptoDoc.cpp | 52 ++++++++++++++++++ client/CryptoDoc.h | 3 ++ client/translations/en.ts | 8 +++ client/translations/et.ts | 8 +++ client/translations/ru.ts | 8 +++ client/widgets/AddressItem.cpp | 98 ++++++++++++++++++---------------- client/widgets/AddressItem.h | 2 - client/widgets/AddressItem.ui | 44 +++++++++++---- 9 files changed, 172 insertions(+), 65 deletions(-) diff --git a/client/CDoc2.cpp b/client/CDoc2.cpp index 853af318..215d00c6 100644 --- a/client/CDoc2.cpp +++ b/client/CDoc2.cpp @@ -495,7 +495,10 @@ CDoc2::CDoc2(const QString &path) CKey CDoc2::canDecrypt(const QSslCertificate &cert) const { - return keys.value(keys.indexOf(CKey(cert))); + auto key = keys.value(keys.indexOf(CKey(cert))); + if(key.unsupported || (!key.transaction_id.isEmpty() && cert.expiryDate() <= QDateTime::currentDateTimeUtc())) + return {}; + return key; } bool CDoc2::decryptPayload(const QByteArray &fmk) @@ -558,6 +561,7 @@ bool CDoc2::save(const QString &path) if(!cdoc20::checkConnection()) return false; QScopedPointer nam(CheckConnection::setupNAM(req, Settings::CDOC2_POST_CERT)); + req.setRawHeader("x-expiry-time", QDateTime::currentDateTimeUtc().addMonths(6).toString(Qt::ISODate).toLatin1()); QEventLoop e; QNetworkReply *reply = nam->post(req, QJsonDocument({ {QLatin1String("recipient_id"), QLatin1String(recipient_id.toBase64())}, @@ -598,7 +602,7 @@ bool CDoc2::save(const QString &path) toVector(key.key), toVector(encrytpedKek)); recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder, cdoc20::Recipients::Capsule::RSAPublicKeyCapsule, rsaPublicKey.Union(), - toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); + toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); continue; } @@ -610,7 +614,7 @@ bool CDoc2::save(const QString &path) rsaKeyServer.Union(), toString(key.keyserver_id), toString(key.transaction_id)); recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder, cdoc20::Recipients::Capsule::KeyServerCapsule, keyServer.Union(), - toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); + toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); continue; } @@ -638,7 +642,7 @@ bool CDoc2::save(const QString &path) cdoc20::Recipients::EllipticCurve::secp384r1, toVector(key.key), toVector(ephPublicKeyDer)); recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder, cdoc20::Recipients::Capsule::ECCPublicKeyCapsule, eccPublicKey.Union(), - toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); + toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); continue; } @@ -651,7 +655,7 @@ bool CDoc2::save(const QString &path) eccKeyServer.Union(), toString(key.keyserver_id), toString(key.transaction_id)); recipients.push_back(cdoc20::Header::CreateRecipientRecord(builder, cdoc20::Recipients::Capsule::KeyServerCapsule, keyServer.Union(), - toString(key.recipient), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); + toString(key.toKeyLabel()), toVector(xor_key), cdoc20::Header::FMKEncryptionMethod::XOR)); } auto offset = cdoc20::Header::CreateHeader(builder, builder.CreateVector(recipients), diff --git a/client/CryptoDoc.cpp b/client/CryptoDoc.cpp index 442ebf6a..6c90f740 100644 --- a/client/CryptoDoc.cpp +++ b/client/CryptoDoc.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -250,6 +251,57 @@ void CKey::setCert(const QSslCertificate &c) isRSA = k.algorithm() == QSsl::Rsa; } +QUrlQuery CKey::fromKeyLabel() const +{ + if(!recipient.startsWith(QLatin1String("data:"), Qt::CaseInsensitive)) + return {}; + QString payload = recipient.mid(5); + QString mimeType; + QString encoding; + if(auto pos = payload.indexOf(','); pos != -1) + { + mimeType = payload.left(pos); + payload = payload.mid(pos + 1); + if(auto header = mimeType.split(';'); header.size() == 2) + { + mimeType = header.value(0); + encoding = header.value(1); + } + } + if(!mimeType.isEmpty() && mimeType != QLatin1String("application/x-www-form-urlencoded")) + return {}; + if(encoding == QLatin1String("base64")) + payload = QByteArray::fromBase64(payload.toLatin1()); + QUrlQuery query(payload); + if(!query.hasQueryItem(QStringLiteral("type")) || !query.hasQueryItem(QStringLiteral("v"))) + query.clear(); + return query; +} + +QString CKey::toKeyLabel() const +{ + if(cert.isNull()) + return recipient; + QDateTime exp = cert.expiryDate(); + if(Settings::CDOC2_USE_KEYSERVER) + exp = std::min(exp, QDateTime::currentDateTimeUtc().addMonths(6)); + auto escape = [](QString data) { return data.replace(',', QLatin1String("%2C")); }; + QString type = QStringLiteral("ID-card"); + if(auto t = SslCertificate(cert).type(); t & SslCertificate::EResidentSubType) + type = QStringLiteral("Digi-ID E-RESIDENT"); + else if(t & SslCertificate::DigiIDType) + type = QStringLiteral("Digi-ID"); + QUrlQuery q; + q.setQueryItems({ + {QStringLiteral("v"), QString::number(1)}, + {QStringLiteral("type"), type}, + {QStringLiteral("serial_number"), escape(cert.subjectInfo("serialNumber").join(','))}, + {QStringLiteral("cn"), escape(cert.subjectInfo("CN").join(','))}, + {QStringLiteral("server_exp"), QString::number(exp.toSecsSinceEpoch())}, + }); + return "data:" + q.query(QUrl::FullyEncoded); +} + CryptoDoc::CryptoDoc( QObject *parent ) diff --git a/client/CryptoDoc.h b/client/CryptoDoc.h index fc490392..8dab84ca 100644 --- a/client/CryptoDoc.h +++ b/client/CryptoDoc.h @@ -28,6 +28,7 @@ #include class QSslKey; +class QUrlQuery; class CKey { @@ -43,6 +44,8 @@ class CKey bool operator==(const CKey &other) const { return other.key == key; } void setCert(const QSslCertificate &c); + QUrlQuery fromKeyLabel() const; + QString toKeyLabel() const; QByteArray key, cipher, publicKey; QSslCertificate cert; diff --git a/client/translations/en.ts b/client/translations/en.ts index a7706017..92ae6c55 100644 --- a/client/translations/en.ts +++ b/client/translations/en.ts @@ -151,6 +151,14 @@ Unsupported cryptographic algorithm or recipient type Unsupported cryptographic algorithm or recipient type + + Decryption is possible until: + Decryption is possible until: + + + Decryption has expired + Decryption has expired + Application diff --git a/client/translations/et.ts b/client/translations/et.ts index 389366d0..25be2664 100644 --- a/client/translations/et.ts +++ b/client/translations/et.ts @@ -151,6 +151,14 @@ Unsupported cryptographic algorithm or recipient type Mittetoetatud krüptograafiline algoritm või adressaadi tüüp + + Decryption is possible until: + Dekrüpteerimine on võimalik kuni: + + + Decryption has expired + Dekrüpteerimine on aegunud + Application diff --git a/client/translations/ru.ts b/client/translations/ru.ts index 1a9c01da..eb725d46 100644 --- a/client/translations/ru.ts +++ b/client/translations/ru.ts @@ -151,6 +151,14 @@ Unsupported cryptographic algorithm or recipient type Неподдерживаемый криптографический алгоритм или тип получателя + + Decryption is possible until: + Расшифровка возможна до: + + + Decryption has expired + Срок расшифровки истек + Application diff --git a/client/widgets/AddressItem.cpp b/client/widgets/AddressItem.cpp index 2d06df9a..479a06e2 100644 --- a/client/widgets/AddressItem.cpp +++ b/client/widgets/AddressItem.cpp @@ -23,9 +23,10 @@ #include "CryptoDoc.h" #include "DateTime.h" #include "SslCertificate.h" -#include "Styles.h" #include "dialogs/KeyDialog.h" +#include + using namespace ria::qdigidoc4; class AddressItem::Private: public Ui::AddressItem @@ -46,27 +47,23 @@ AddressItem::AddressItem(CKey k, QWidget *parent, bool showIcon) if(showIcon) ui->icon->load(QStringLiteral(":/images/icon_Krypto_small.svg")); ui->icon->setVisible(showIcon); - ui->name->setFont(Styles::font(Styles::Regular, 14, QFont::DemiBold)); - ui->name->installEventFilter(this); - ui->idType->setFont(Styles::font(Styles::Regular, 11)); - ui->idType->installEventFilter(this); connect(ui->add, &QToolButton::clicked, this, [this]{ emit add(this);}); connect(ui->remove, &QToolButton::clicked, this, [this]{ emit remove(this);}); - ui->add->setFont(Styles::font(Styles::Condensed, 12)); - ui->added->setFont(ui->add->font()); - ui->code = SslCertificate(ui->key.cert).personalCode().toHtmlEscaped(); ui->label = (!ui->key.cert.subjectInfo("GN").isEmpty() && !ui->key.cert.subjectInfo("SN").isEmpty() ? ui->key.cert.subjectInfo("GN").join(' ') + " " + ui->key.cert.subjectInfo("SN").join(' ') : ui->key.cert.subjectInfo("CN").join(' ')).toHtmlEscaped(); if(ui->label.isEmpty()) - ui->label = ui->key.recipient.toHtmlEscaped(); + { + if(QUrlQuery q = ui->key.fromKeyLabel(); !q.isEmpty()) + ui->label = q.queryItemValue(QStringLiteral("cn"), QUrl::FullyDecoded).toHtmlEscaped(); + else + ui->label = ui->key.recipient.toHtmlEscaped(); + } setIdType(); showButton(AddressItem::Remove); - if(ui->key.unsupported) - ui->idType->setText(tr("Unsupported cryptographic algorithm or recipient type")); } AddressItem::~AddressItem() @@ -85,37 +82,24 @@ void AddressItem::changeEvent(QEvent* event) QWidget::changeEvent(event); } -bool AddressItem::eventFilter(QObject *o, QEvent *e) -{ - if((o == ui->name || o == ui->idType) && e->type() == QEvent::MouseButtonRelease) - { - (new KeyDialog(ui->key, this))->open(); - return true; - } - return Item::eventFilter(o, e); -} - const CKey& AddressItem::getKey() const { return ui->key; } -void AddressItem::idChanged(const CKey &key) +void AddressItem::idChanged(const SslCertificate &cert) { + CKey key(cert); ui->yourself = !key.key.isNull() && ui->key == key; setName(); } -void AddressItem::idChanged(const SslCertificate &cert) -{ - idChanged(CKey(cert)); -} - void AddressItem::initTabOrder(QWidget *item) { setTabOrder(item, ui->name); setTabOrder(ui->name, ui->idType); - setTabOrder(ui->idType, ui->remove); + setTabOrder(ui->idType, ui->expire); + setTabOrder(ui->expire, ui->remove); setTabOrder(ui->remove, ui->added); setTabOrder(ui->added, lastTabWidget()); } @@ -127,7 +111,8 @@ QWidget* AddressItem::lastTabWidget() void AddressItem::mouseReleaseEvent(QMouseEvent * /*event*/) { - (new KeyDialog(ui->key, this))->open(); + if(!ui->key.unsupported) + (new KeyDialog(ui->key, this))->open(); } void AddressItem::setName() @@ -152,33 +137,52 @@ void AddressItem::stateChange(ContainerState state) void AddressItem::setIdType() { - ui->idType->setHidden(ui->key.cert.isNull()); - if(ui->key.cert.isNull()) - return; - - QString str; + ui->expire->clear(); SslCertificate cert(ui->key.cert); SslCertificate::CertType type = cert.type(); - if(type & SslCertificate::DigiIDType) - str = tr("digi-ID"); + if(ui->key.unsupported) + { + ui->label = tr("Unsupported cryptographic algorithm or recipient type"); + ui->idType->clear(); + } + else if(type & SslCertificate::DigiIDType) + ui->idType->setText(tr("digi-ID")); else if(type & SslCertificate::EstEidType) - str = tr("ID-card"); + ui->idType->setText(tr("ID-card")); else if(type & SslCertificate::MobileIDType) - str = tr("mobile-ID"); + ui->idType->setText(tr("mobile-ID")); else if(type & SslCertificate::TempelType) { if(cert.keyUsage().contains(SslCertificate::NonRepudiation)) - str = tr("e-Seal"); + ui->idType->setText(tr("e-Seal")); else if(cert.enhancedKeyUsage().contains(SslCertificate::ClientAuth)) - str = tr("Authentication certificate"); + ui->idType->setText(tr("Authentication certificate")); else - str = tr("Certificate for Encryption"); + ui->idType->setText(tr("Certificate for Encryption")); + } + else + { + QUrlQuery q = ui->key.fromKeyLabel(); + ui->idType->setText(q.queryItemValue(QStringLiteral("type"), QUrl::FullyDecoded).toHtmlEscaped()); + if(QString server_exp = q.queryItemValue(QStringLiteral("server_exp"), QUrl::FullyDecoded); !server_exp.isEmpty()) + { + auto date = QDateTime::fromSecsSinceEpoch(server_exp.toLongLong()); + bool canDecrypt = QDateTime::currentDateTimeUtc() < date; + ui->expire->setProperty("label", canDecrypt ? QStringLiteral("good") : QStringLiteral("error")); + ui->expire->setText(canDecrypt ? QStringLiteral("%1 %2").arg( + tr("Decryption is possible until:"), DateTime(date.toLocalTime()).formatDate(QStringLiteral("dd. MMMM yyyy"))) : + tr("Decryption has expired")); + } + } + + if(!cert.isNull()) + { + ui->expire->setProperty("label", QStringLiteral("default")); + ui->expire->setText(QStringLiteral("%1 %2").arg( + cert.isValid() ? tr("Expires on") : tr("Expired on"), + DateTime(cert.expiryDate().toLocalTime()).formatDate(QStringLiteral("dd. MMMM yyyy")))); } - if(!str.isEmpty()) - str += QStringLiteral(" - "); - DateTime date(cert.expiryDate().toLocalTime()); - ui->idType->setText(QStringLiteral("%1%2 %3").arg(str, - cert.isValid() ? tr("Expires on") : tr("Expired on"), - date.formatDate(QStringLiteral("dd. MMMM yyyy")))); + ui->idType->setHidden(ui->idType->text().isEmpty()); + ui->expire->setHidden(ui->expire->text().isEmpty()); } diff --git a/client/widgets/AddressItem.h b/client/widgets/AddressItem.h index 9f04c09f..d6ce8a57 100644 --- a/client/widgets/AddressItem.h +++ b/client/widgets/AddressItem.h @@ -39,7 +39,6 @@ class AddressItem final : public Item ~AddressItem() final; const CKey& getKey() const; - void idChanged(const CKey &cert); void idChanged(const SslCertificate &cert) final; void initTabOrder(QWidget *item) final; QWidget* lastTabWidget() final; @@ -48,7 +47,6 @@ class AddressItem final : public Item private: void changeEvent(QEvent *event) final; - bool eventFilter(QObject *o, QEvent *e) final; void mouseReleaseEvent(QMouseEvent *event) final; void setName(); void setIdType(); diff --git a/client/widgets/AddressItem.ui b/client/widgets/AddressItem.ui index e32d134a..1ab219cf 100644 --- a/client/widgets/AddressItem.ui +++ b/client/widgets/AddressItem.ui @@ -14,17 +14,16 @@ PointingHandCursor - QWidget { -font-family: Roboto, Helvetica; -font-size: 12px; -} -#AddressItem { + #AddressItem { border-bottom: 1px solid rgba(217, 217, 216, 0.45); background-color: #FFFFFF; } #AddressItem:disabled { background-color: #F0F0F2; } +#AddressItem > QWidget { +font-family: Roboto, Helvetica; +} #name { color: #07142A; font-size: 14px; @@ -32,14 +31,31 @@ font-weight: 700; } #idType { color: #07142A; +font-size: 12px; } -#expire { +QLabel[label="default"] { color: #07142A; +font-size: 12px; background: #F3F5F7; padding: 2px 8px; border-radius: 8px; } +QLabel[label="error"] { +color: #AD2A45; +font-size: 12px; +background: #F5EBED; +padding: 2px 8px; +border-radius: 8px; +} +QLabel[label="good"] { +color: #1A641B; +font-size: 12px; +background: #EAF8EA; +padding: 2px 8px; +border-radius: 8px; +} QToolButton { +font-size: 12px; font-weight: 700; border-radius: 2px; border: none; @@ -95,7 +111,7 @@ color: #727679; - Qt::FocusPolicy::TabFocus + Qt::TabFocus MARI MAASIKAS MUSTIKAS 48405050123 (Sina ise) @@ -108,7 +124,7 @@ color: #727679; - Qt::FocusPolicy::TabFocus + Qt::TabFocus ID-card @@ -117,20 +133,26 @@ color: #727679; + + Qt::TabFocus + Expire + + default + - Qt::Orientation::Horizontal + Qt::Horizontal 40 - 20 + 0 @@ -214,7 +236,7 @@ color: #727679; QSvgWidget QWidget -
QtSvg/QSvgWidget
+
QSvgWidget
1