diff --git a/client/Application.cpp b/client/Application.cpp index 66b4107d5..0ae71e3d3 100644 --- a/client/Application.cpp +++ b/client/Application.cpp @@ -302,9 +302,6 @@ class Application::Private QString lang; QTimer lastWindowTimer; volatile bool ready = false; -#ifdef Q_OS_WIN - QStringList tempFiles; -#endif // Q_OS_WIN ~Private() { delete signer; @@ -520,11 +517,6 @@ Application::~Application() { for(QWidget *top: topLevelWidgets()) top->close(); -#ifdef Q_OS_WIN - for(const QString &file: qAsConst(d->tempFiles)) - QFile::remove(file); - d->tempFiles.clear(); -#endif // Q_OS_WIN #ifndef Q_OS_MAC if( isRunning() ) @@ -559,13 +551,6 @@ Application::~Application() void Application::addRecent( const QString & ) {} #endif -#ifdef Q_OS_WIN -void Application::addTempFile(const QString &file) -{ - d->tempFiles.append(file); -} -#endif - void Application::browse( const QUrl &url ) { QUrl u = url; diff --git a/client/Application.h b/client/Application.h index c458af40a..f8d30ec8a 100644 --- a/client/Application.h +++ b/client/Application.h @@ -55,9 +55,6 @@ class Application final: public BaseApplication explicit Application( int &argc, char **argv ); ~Application() final; -#ifdef Q_OS_WIN - void addTempFile(const QString &file); -#endif Configuration *conf(); void loadTranslation( const QString &lang ); bool notify(QObject *object, QEvent *event ) final; diff --git a/client/QPKCS11.cpp b/client/QPKCS11.cpp index 919ce2eaf..28479d0a7 100644 --- a/client/QPKCS11.cpp +++ b/client/QPKCS11.cpp @@ -32,8 +32,6 @@ #include #include -#include - #include #include #include @@ -339,7 +337,7 @@ QByteArray QPKCS11::deriveHMACExtract(const QByteArray &publicKey, const QByteAr QByteArray key = derive(publicKey); if(key.isEmpty()) return key; - auto ctx = libcdoc::make_unique_ptr(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr)); + auto ctx = make_unique_ptr(EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr)); QByteArray out(keySize, 0); auto outlen = size_t(out.length()); auto isError = [this](int err) { diff --git a/client/SslCertificate.cpp b/client/SslCertificate.cpp index f43e29df3..c1281fce0 100644 --- a/client/SslCertificate.cpp +++ b/client/SslCertificate.cpp @@ -20,6 +20,7 @@ #include "SslCertificate.h" #include "Common.h" +#include "Utils.h" #include #include @@ -35,18 +36,6 @@ #include #include -#include - -template -struct free_deleter -{ - template - void operator()(T *p) const noexcept - { - D(p); - } -}; - template struct free_argument; template struct free_argument @@ -59,13 +48,6 @@ struct free_argument using type = T; }; -template -[[nodiscard]] -constexpr auto make_unique_ptr(T *t) noexcept -{ - return std::unique_ptr>(t); -} - template static auto toQByteArray(T &x) { diff --git a/client/Utils.h b/client/Utils.h index c8c317fe7..39a88a0ba 100644 --- a/client/Utils.h +++ b/client/Utils.h @@ -25,9 +25,27 @@ #include #include +#include #include namespace { + template + struct free_deleter + { + template + void operator()(T *p) const noexcept + { + F(p); + } + }; + + template + [[nodiscard]] + constexpr auto make_unique_ptr(T *t) noexcept + { + return std::unique_ptr>(t); + } + template inline auto waitFor(F&& function, Args&& ...args) { std::exception_ptr exception; diff --git a/client/dialogs/CertificateDetails.cpp b/client/dialogs/CertificateDetails.cpp index f679e3ae7..8448ee706 100644 --- a/client/dialogs/CertificateDetails.cpp +++ b/client/dialogs/CertificateDetails.cpp @@ -21,24 +21,30 @@ #include "CertificateDetails.h" #include "ui_CertificateDetails.h" -#include "Application.h" #include "DateTime.h" #include "SslCertificate.h" +#include "Utils.h" #include "effects/Overlay.h" #include "dialogs/WarningDialog.h" #include #include #include -#include #include #include +#ifdef Q_OS_WIN +#include +#include +#include +#endif + CertificateDetails::CertificateDetails(const SslCertificate &cert, QWidget *parent) : QDialog(parent) { Ui::CertificateDetails ui; ui.setupUi(this); + setAttribute(Qt::WA_DeleteOnClose); #ifdef Q_OS_MAC setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::Sheet); #else @@ -46,17 +52,19 @@ CertificateDetails::CertificateDetails(const SslCertificate &cert, QWidget *pare #endif new Overlay(this); + const QHash enhancedKeyUsageHash = cert.enhancedKeyUsage(); + QString i; QTextStream s( &i ); s << "" << tr("This certificate is intended for following purpose(s):") << ""; s << "
    "; - for(const QString &ext: cert.enhancedKeyUsage()) - s << "
  • " << tr(ext.toStdString().c_str()) << "
  • "; + for(const QString &ext: enhancedKeyUsageHash) + s << "
  • " << ext << "
  • "; s << "
"; s << "
"; - s << "" << tr("Issued to:") << "
" << cert.subjectInfo( QSslCertificate::CommonName); + s << "" << tr("Issued to:") << "
" << cert.subjectInfo( QSslCertificate::CommonName).toHtmlEscaped(); s << "

"; - s << "" << tr("Issued by:") << "
" << cert.issuerInfo(QSslCertificate::CommonName); + s << "" << tr("Issued by:") << "
" << cert.issuerInfo(QSslCertificate::CommonName).toHtmlEscaped(); s << "

"; s << "" << tr("Valid:") << "
"; s << "" << tr("From") << " " << cert.effectiveDate().toLocalTime().toString(QStringLiteral("dd.MM.yyyy")) << "
"; @@ -72,9 +80,7 @@ CertificateDetails::CertificateDetails(const SslCertificate &cert, QWidget *pare if( file.isEmpty() ) return; - if(QFile f(file); f.open(QIODevice::WriteOnly)) - f.write(cert.toPem()); - else + if(QFile f(file); !f.open(QIODevice::WriteOnly) || f.write(cert.toPem()) < 0) WarningDialog::create(this)->withTitle(QCoreApplication::translate("FileDialog", "Failed to save file"))->open(); }); connect(ui.close, &QPushButton::clicked, this, &CertificateDetails::accept); @@ -98,48 +104,38 @@ CertificateDetails::CertificateDetails(const SslCertificate &cert, QWidget *pare tblDetails->setItem(row, 1, item); }; - addItem(tr("Version"), QString("V" + cert.version())); + auto joinInfo = [](const QList &attrs, auto infoFn) { + QStringList text, textExt; + for(const QByteArray &obj: attrs) + { + QString data = infoFn(obj); + if(data.isEmpty()) + continue; + textExt.append(QStringLiteral("%1 = %2").arg(obj.constData(), data)); + text.append(std::move(data)); + } + return std::pair(text.join(QStringLiteral(", ")), textExt.join('\n')); + }; + + addItem(tr("Version"), "V" + cert.version()); addItem(tr("Serial number"), cert.serialNumber()); addItem(tr("Signature algorithm"), cert.signatureAlgorithm()); - - QStringList text, textExt; - static const QByteArray ORGID_OID = QByteArrayLiteral("2.5.4.97"); - for(const QByteArray &obj: cert.issuerInfoAttributes()) - { - const QString &data = cert.issuerInfo( obj ); - if( data.isEmpty() ) - continue; - text << data; - // organizationIdentifier OID might not be known by SSL backend - textExt << QStringLiteral("%1 = %2").arg( - obj.constData() == ORGID_OID ? "organizationIdentifier" : obj.constData(), data); - } - addItem(tr("Issuer"), text.join(QStringLiteral(", ")), textExt.join('\n')); + auto [issuerText, issuerTextExt] = joinInfo(cert.issuerInfoAttributes(), + [&cert](const QByteArray &obj) { return cert.issuerInfo(obj); }); + addItem(tr("Issuer"), issuerText, issuerTextExt); addItem(tr("Valid from"), DateTime(cert.effectiveDate().toLocalTime()).toStringZ(QStringLiteral("dd.MM.yyyy hh:mm:ss"))); addItem(tr("Valid to"), DateTime(cert.expiryDate().toLocalTime()).toStringZ(QStringLiteral("dd.MM.yyyy hh:mm:ss"))); - - text.clear(); - textExt.clear(); - for(const QByteArray &obj: cert.subjectInfoAttributes()) - { - const QString &data = cert.subjectInfo( obj ); - if( data.isEmpty() ) - continue; - text << data; - textExt << QStringLiteral("%1 = %2").arg(obj.constData(), data); - } - addItem(tr("Subject"), text.join(QStringLiteral(", ")), textExt.join('\n')); + auto [subjectText, subjectTextExt] = joinInfo(cert.subjectInfoAttributes(), + [&cert](const QByteArray &obj) { return cert.subjectInfo(obj); }); + addItem(tr("Subject"), subjectText, subjectTextExt); addItem(tr("Public key"), cert.keyName(), cert.publicKey().toDer().toHex(' ').toUpper()); - QStringList enhancedKeyUsage = cert.enhancedKeyUsage().values(); - if( !enhancedKeyUsage.isEmpty() ) + if(QStringList enhancedKeyUsage = enhancedKeyUsageHash.values(); !enhancedKeyUsage.isEmpty()) addItem(tr("Enhanced key usage"), enhancedKeyUsage.join(QStringLiteral(", ")), enhancedKeyUsage.join('\n')); - QStringList policies = cert.policies(); - if( !policies.isEmpty() ) + if(QStringList policies = cert.policies(); !policies.isEmpty()) addItem(tr("Certificate policies"), policies.join(QStringLiteral(", "))); addItem(tr("Authority key identifier"), cert.authorityKeyIdentifier().toHex(' ').toUpper()); addItem(tr("Subject key identifier"), cert.subjectKeyIdentifier().toHex(' ').toUpper()); - QStringList keyUsage = cert.keyUsage().values(); - if( !keyUsage.isEmpty() ) + if(QStringList keyUsage = cert.keyUsage().values(); !keyUsage.isEmpty()) addItem(tr("Key usage"), keyUsage.join(QStringLiteral(", ")), keyUsage.join('\n')); // Disable resizing @@ -150,17 +146,17 @@ CertificateDetails::CertificateDetails(const SslCertificate &cert, QWidget *pare void CertificateDetails::showCertificate(const QSslCertificate &cert, QWidget *parent, const QString &suffix) { #ifdef Q_OS_UNIX - CertificateDetails(cert, parent).exec(); + (new CertificateDetails(cert, parent))->open(); #else - Q_UNUSED(parent); - QString name = cert.subjectInfo("serialNumber").join('_'); - if(name.isEmpty()) - name = cert.serialNumber().replace(':', ""); - QString path = QStringLiteral("%1/%2%3.cer").arg(QDir::tempPath(), name, suffix); - if(QFile f(path); f.open(QIODevice::WriteOnly)) - f.write(cert.toPem()); - qApp->addTempFile(path); - QDesktopServices::openUrl(QUrl::fromLocalFile(path)); + Q_UNUSED(suffix); + QByteArray der = cert.toDer(); + if(auto ctx = make_unique_ptr(CertCreateCertificateContext( + X509_ASN_ENCODING, LPBYTE(der.constData()), DWORD(der.size())))) + { + CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, ctx.get(), + parent && parent->window() ? HWND(parent->window()->winId()) : nullptr, + nullptr, 0, nullptr); + } #endif } #endif