diff --git a/src/commands/certifycertificatecommand.cpp b/src/commands/certifycertificatecommand.cpp index a9acea77f..da3e8450a 100644 --- a/src/commands/certifycertificatecommand.cpp +++ b/src/commands/certifycertificatecommand.cpp @@ -1,344 +1,343 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/signcertificatecommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2019 g10code GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "certifycertificatecommand.h" #include "newopenpgpcertificatecommand.h" #include "command_p.h" #include "dialogs/certifycertificatedialog.h" #include "exportopenpgpcertstoservercommand.h" #include "utils/keys.h" #include "utils/tags.h" #include #include #include #include #include #include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace Kleo::Commands; using namespace GpgME; using namespace QGpgME; class CertifyCertificateCommand::Private : public Command::Private { friend class ::Kleo::Commands::CertifyCertificateCommand; CertifyCertificateCommand *q_func() const { return static_cast(q); } public: explicit Private(CertifyCertificateCommand *qq, KeyListController *c); ~Private() override; void init(); private: void slotDialogRejected(); void slotResult(const Error &err); void slotCertificationPrepared(); private: void ensureDialogCreated(); void createJob(); private: GpgME::Key target; std::vector uids; QPointer dialog; QPointer job; }; CertifyCertificateCommand::Private *CertifyCertificateCommand::d_func() { return static_cast(d.get()); } const CertifyCertificateCommand::Private *CertifyCertificateCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() CertifyCertificateCommand::Private::Private(CertifyCertificateCommand *qq, KeyListController *c) : Command::Private(qq, c) , uids() , dialog() , job() { } CertifyCertificateCommand::Private::~Private() { qCDebug(KLEOPATRA_LOG); if (dialog) { delete dialog; dialog = nullptr; } } CertifyCertificateCommand::CertifyCertificateCommand(KeyListController *c) : Command(new Private(this, c)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(QAbstractItemView *v, KeyListController *c) : Command(v, new Private(this, c)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const GpgME::Key &key) : Command(key, new Private(this, nullptr)) { d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const GpgME::UserID &uid) : Command(uid.parent(), new Private(this, nullptr)) { std::vector(1, uid).swap(d->uids); d->init(); } CertifyCertificateCommand::CertifyCertificateCommand(const std::vector &uids) : Command(uids.empty() ? Key() : uids.front().parent(), new Private(this, nullptr)) { d->uids = uids; d->init(); } void CertifyCertificateCommand::Private::init() { } CertifyCertificateCommand::~CertifyCertificateCommand() { qCDebug(KLEOPATRA_LOG); } void CertifyCertificateCommand::doStart() { const std::vector keys = d->keys(); if (keys.size() != 1 || keys.front().protocol() != GpgME::OpenPGP) { d->finished(); return; } // hold on to the key to certify to avoid invalidation during refreshes of the key cache d->target = keys.front(); if (d->target.isExpired() || d->target.isRevoked()) { const auto title = d->target.isRevoked() ? i18nc("@title:window", "Key is Revoked") : i18nc("@title:window", "Key is Expired"); const auto message = d->target.isRevoked() // ? i18nc("@info", "This key has been revoked. You cannot certify it.") : i18nc("@info", "This key has expired. You cannot certify it."); d->information(message, title); d->finished(); return; } auto findAnyGoodKey = []() { const std::vector secKeys = KeyCache::instance()->secretKeys(); return std::any_of(secKeys.cbegin(), secKeys.cend(), [](const Key &secKey) { return secKey.canCertify() && secKey.protocol() == OpenPGP && !secKey.isRevoked() && !secKey.isExpired() && !secKey.isInvalid(); }); }; if (!findAnyGoodKey()) { auto sel = KMessageBox::questionTwoActions(d->parentWidgetOrView(), xi18nc("@info", "To certify other certificates, you first need to create an OpenPGP certificate for yourself.") + QStringLiteral("

") + i18n("Do you wish to create one now?"), i18n("Certification Not Possible"), KGuiItem(i18n("Create")), KStandardGuiItem::cancel()); if (sel == KMessageBox::ButtonCode::PrimaryAction) { QEventLoop loop; auto cmd = new NewOpenPGPCertificateCommand; cmd->setParentWidget(d->parentWidgetOrView()); connect(cmd, &Command::finished, &loop, &QEventLoop::quit); QMetaObject::invokeMethod(cmd, &NewOpenPGPCertificateCommand::start, Qt::QueuedConnection); loop.exec(); } else { Q_EMIT(canceled()); d->finished(); return; } // Check again for secret keys if (!findAnyGoodKey()) { qCDebug(KLEOPATRA_LOG) << "Sec Keys still empty after keygen."; Q_EMIT(canceled()); d->finished(); return; } } const char *primary = keys.front().primaryFingerprint(); const bool anyMismatch = std::any_of(d->uids.cbegin(), d->uids.cend(), [primary](const UserID &uid) { return qstricmp(uid.parent().primaryFingerprint(), primary) != 0; }); if (anyMismatch) { qCWarning(KLEOPATRA_LOG) << "User ID <-> Key mismatch!"; d->finished(); return; } d->ensureDialogCreated(); Q_ASSERT(d->dialog); d->dialog->setCertificateToCertify(d->target, d->uids); d->dialog->show(); } void CertifyCertificateCommand::Private::slotDialogRejected() { Q_EMIT q->canceled(); finished(); } void CertifyCertificateCommand::Private::slotResult(const Error &err) { if (err.isCanceled()) { // do nothing } else if (err) { error(i18n("

An error occurred while trying to certify

" "%1:

\t%2

", Formatting::formatForComboBox(target), Formatting::errorAsString(err)), i18n("Certification Error")); } else if (dialog && dialog->exportableCertificationSelected() && dialog->sendToServer()) { auto const cmd = new ExportOpenPGPCertsToServerCommand(target); cmd->start(); } else { information(i18n("Certification successful."), i18n("Certification Succeeded")); } if (!dialog->tags().isEmpty()) { Tags::enableTags(); } finished(); } void CertifyCertificateCommand::Private::slotCertificationPrepared() { Q_ASSERT(dialog); const auto selectedUserIds = dialog->selectedUserIDs(); std::vector userIdIndexes; userIdIndexes.reserve(selectedUserIds.size()); for (unsigned int i = 0, numUserIds = target.numUserIDs(); i < numUserIds; ++i) { const auto userId = target.userID(i); const bool userIdIsSelected = Kleo::any_of(selectedUserIds, [userId](const auto &uid) { return Kleo::userIDsAreEqual(userId, uid); }); if (userIdIsSelected) { userIdIndexes.push_back(i); } } createJob(); Q_ASSERT(job); job->setExportable(dialog->exportableCertificationSelected()); - job->setNonRevocable(dialog->nonRevocableCertificationSelected()); job->setUserIDsToSign(userIdIndexes); job->setSigningKey(dialog->selectedSecretKey()); if (!dialog->tags().isEmpty()) { // do not set an empty remark to avoid an empty signature notation (GnuPG bug T5142) job->setRemark(dialog->tags()); } job->setDupeOk(true); if (dialog->trustSignatureSelected() && !dialog->trustSignatureDomain().isEmpty()) { // always create level 1 trust signatures with complete trust job->setTrustSignature(TrustSignatureTrust::Complete, 1, dialog->trustSignatureDomain()); } if (!dialog->expirationDate().isNull()) { job->setExpirationDate(dialog->expirationDate()); } if (const Error err = job->start(target)) { slotResult(err); } } void CertifyCertificateCommand::doCancel() { qCDebug(KLEOPATRA_LOG); if (d->job) { d->job->slotCancel(); } } void CertifyCertificateCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new CertifyCertificateDialog; applyWindowID(dialog); connect(dialog, &QDialog::rejected, q, [this]() { slotDialogRejected(); }); connect(dialog, &QDialog::accepted, q, [this]() { slotCertificationPrepared(); }); } void CertifyCertificateCommand::Private::createJob() { Q_ASSERT(!job); Q_ASSERT(target.protocol() == OpenPGP); const auto backend = QGpgME::openpgp(); if (!backend) { return; } SignKeyJob *const j = backend->signKeyJob(); if (!j) { return; } #if QGPGME_JOB_HAS_NEW_PROGRESS_SIGNALS connect(j, &QGpgME::Job::jobProgress, q, &Command::progress); #else connect(j, &QGpgME::Job::progress, q, [this](const QString &, int current, int total) { Q_EMIT q->progress(current, total); }); #endif connect(j, &SignKeyJob::result, q, [this](const GpgME::Error &result) { slotResult(result); }); job = j; } #undef d #undef q #include "moc_certifycertificatecommand.cpp" diff --git a/src/dialogs/certifycertificatedialog.cpp b/src/dialogs/certifycertificatedialog.cpp index 976a5ae30..b83404ae7 100644 --- a/src/dialogs/certifycertificatedialog.cpp +++ b/src/dialogs/certifycertificatedialog.cpp @@ -1,155 +1,150 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/signcertificatedialog.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-FileCopyrightText: 2019 g10code GmbH SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "kleopatra_debug.h" #include "certifycertificatedialog.h" #include "certifywidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace GpgME; using namespace Kleo; CertifyCertificateDialog::CertifyCertificateDialog(QWidget *p, Qt::WindowFlags f) : QDialog(p, f) { setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); // Setup GUI auto mainLay = new QVBoxLayout(this); mCertWidget = new CertifyWidget(this); mainLay->addWidget(mCertWidget); auto buttonBox = new QDialogButtonBox{this}; buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok); const auto okButton = buttonBox->button(QDialogButtonBox::Ok); KGuiItem::assign(okButton, KStandardGuiItem::ok()); okButton->setText(i18n("Certify")); KGuiItem::assign(buttonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel()); connect(buttonBox, &QDialogButtonBox::accepted, this, &CertifyCertificateDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close); mainLay->addWidget(buttonBox); okButton->setEnabled(mCertWidget->isValid()); connect(mCertWidget, &CertifyWidget::changed, this, [this, okButton]() { okButton->setEnabled(mCertWidget->isValid()); }); KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CertifyDialog"); const auto size = cfgGroup.readEntry("Size", QSize{640, 480}); if (size.isValid()) { resize(size); } } CertifyCertificateDialog::~CertifyCertificateDialog() { KConfigGroup cfgGroup(KSharedConfig::openStateConfig(), "CertifyDialog"); cfgGroup.writeEntry("Size", size()); cfgGroup.sync(); } void CertifyCertificateDialog::setCertificateToCertify(const Key &key, const std::vector &uids) { Q_ASSERT(Kleo::all_of(uids, [key](const auto &uid) { return Kleo::userIDBelongsToKey(uid, key); })); setWindowTitle(i18nc("@title:window arg is name, email of certificate holder", "Certify Certificate: %1", Formatting::prettyName(key))); mCertWidget->setCertificate(key, uids); } bool CertifyCertificateDialog::exportableCertificationSelected() const { return mCertWidget->exportableSelected(); } bool CertifyCertificateDialog::trustSignatureSelected() const { return mCertWidget->trustSignatureSelected(); } QString CertifyCertificateDialog::trustSignatureDomain() const { return mCertWidget->trustSignatureDomain(); } -bool CertifyCertificateDialog::nonRevocableCertificationSelected() const -{ - return false; -} - Key CertifyCertificateDialog::selectedSecretKey() const { return mCertWidget->secKey(); } bool CertifyCertificateDialog::sendToServer() const { return mCertWidget->publishSelected(); } void CertifyCertificateDialog::setSelectedUserIDs(const std::vector &uids) { mCertWidget->selectUserIDs(uids); } std::vector CertifyCertificateDialog::selectedUserIDs() const { return mCertWidget->selectedUserIDs(); } QString CertifyCertificateDialog::tags() const { return mCertWidget->tags(); } QDate CertifyCertificateDialog::expirationDate() const { return mCertWidget->expirationDate(); } void CertifyCertificateDialog::accept() { if (!mCertWidget->isValid()) { return; } KConfigGroup conf(KSharedConfig::openConfig(), "CertifySettings"); const auto lastKey = mCertWidget->secKey(); if (!lastKey.isNull()) { conf.writeEntry("LastKey", lastKey.primaryFingerprint()); } conf.writeEntry("ExportCheckState", mCertWidget->exportableSelected()); conf.writeEntry("PublishCheckState", mCertWidget->publishSelected()); QDialog::accept(); } diff --git a/src/dialogs/certifycertificatedialog.h b/src/dialogs/certifycertificatedialog.h index a4072115b..76023cf30 100644 --- a/src/dialogs/certifycertificatedialog.h +++ b/src/dialogs/certifycertificatedialog.h @@ -1,59 +1,57 @@ /* -*- mode: c++; c-basic-offset:4 -*- dialogs/signcertificatedialog.h This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once #include #include #include #include namespace Kleo { class CertifyWidget; class CertifyCertificateDialog : public QDialog { Q_OBJECT public: explicit CertifyCertificateDialog(QWidget *parent = nullptr, Qt::WindowFlags f = {}); ~CertifyCertificateDialog() override; void setCertificateToCertify(const GpgME::Key &key, const std::vector &uids = {}); bool exportableCertificationSelected() const; bool trustSignatureSelected() const; QString trustSignatureDomain() const; - bool nonRevocableCertificationSelected() const; - void setSelectedUserIDs(const std::vector &uids); std::vector selectedUserIDs() const; GpgME::Key selectedSecretKey() const; bool sendToServer() const; QString tags() const; QDate expirationDate() const; public Q_SLOTS: void accept() override; private: CertifyWidget *mCertWidget; }; }