diff --git a/src/commands/revokekeycommand.cpp b/src/commands/revokekeycommand.cpp index 09ab3b0f6..57af53ea5 100644 --- a/src/commands/revokekeycommand.cpp +++ b/src/commands/revokekeycommand.cpp @@ -1,246 +1,277 @@ /* -*- mode: c++; c-basic-offset:4 -*- commands/revokekeycommand.cpp This file is part of Kleopatra, the KDE keymanager SPDX-FileCopyrightText: 2022 g10 Code GmbH SPDX-FileContributor: Ingo Klöcker SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "command_p.h" +#include "commands/exportcertificatecommand.h" +#include "commands/exportopenpgpcertstoservercommand.h" #include "dialogs/revokekeydialog.h" #include "revokekeycommand.h" #include +#include +#include #include #include #include "kleopatra_debug.h" #include using namespace Kleo; using namespace GpgME; class RevokeKeyCommand::Private : public Command::Private { friend class ::RevokeKeyCommand; RevokeKeyCommand *q_func() const { return static_cast(q); } public: explicit Private(RevokeKeyCommand *qq, KeyListController *c = nullptr); ~Private() override; void start(); void cancel(); private: void ensureDialogCreated(); void onDialogAccepted(); void onDialogRejected(); std::unique_ptr startJob(); void onJobResult(const Error &err); void showError(const Error &err); private: Key key; QPointer dialog; QPointer job; }; RevokeKeyCommand::Private *RevokeKeyCommand::d_func() { return static_cast(d.get()); } const RevokeKeyCommand::Private *RevokeKeyCommand::d_func() const { return static_cast(d.get()); } #define d d_func() #define q q_func() RevokeKeyCommand::Private::Private(RevokeKeyCommand *qq, KeyListController *c) : Command::Private{qq, c} { } RevokeKeyCommand::Private::~Private() = default; namespace { Key getKey(const std::vector &keys) { if (keys.size() != 1) { qCWarning(KLEOPATRA_LOG) << "Expected exactly one key, but got" << keys.size(); return {}; } const Key key = keys.front(); if (key.protocol() != GpgME::OpenPGP) { qCWarning(KLEOPATRA_LOG) << "Expected OpenPGP key, but got" << Formatting::displayName(key.protocol()) << "key"; return {}; } return key; } } void RevokeKeyCommand::Private::start() { key = getKey(keys()); if (key.isNull()) { finished(); return; } if (key.isRevoked()) { information(i18nc("@info", "This key has already been revoked.")); finished(); return; } ensureDialogCreated(); Q_ASSERT(dialog); dialog->setKey(key); dialog->show(); } void RevokeKeyCommand::Private::cancel() { if (job) { job->slotCancel(); } job.clear(); } void RevokeKeyCommand::Private::ensureDialogCreated() { if (dialog) { return; } dialog = new RevokeKeyDialog; applyWindowID(dialog); dialog->setAttribute(Qt::WA_DeleteOnClose); connect(dialog, &QDialog::accepted, q, [this]() { onDialogAccepted(); }); connect(dialog, &QDialog::rejected, q, [this]() { onDialogRejected(); }); } void RevokeKeyCommand::Private::onDialogAccepted() { auto revokeJob = startJob(); if (!revokeJob) { finished(); return; } job = revokeJob.release(); } void RevokeKeyCommand::Private::onDialogRejected() { canceled(); } namespace { std::vector toStdStrings(const QStringList &l) { std::vector v; v.reserve(l.size()); std::transform(std::begin(l), std::end(l), std::back_inserter(v), std::mem_fn(&QString::toStdString)); return v; } auto descriptionToLines(const QString &description) { std::vector lines; if (!description.isEmpty()) { lines = toStdStrings(description.split(QLatin1Char('\n'))); } return lines; } } std::unique_ptr RevokeKeyCommand::Private::startJob() { std::unique_ptr revokeJob{QGpgME::openpgp()->revokeKeyJob()}; Q_ASSERT(revokeJob); connect(revokeJob.get(), &QGpgME::RevokeKeyJob::result, q, [this](const GpgME::Error &err) { onJobResult(err); }); connect(revokeJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress); const auto description = descriptionToLines(dialog->description()); const GpgME::Error err = revokeJob->start(key, dialog->reason(), description); if (err) { showError(err); return {}; } Q_EMIT q->info(i18nc("@info:status", "Revoking key...")); return revokeJob; } void RevokeKeyCommand::Private::onJobResult(const Error &err) { if (err) { showError(err); finished(); return; } if (!err.isCanceled()) { information(i18nc("@info", "The key was revoked successfully."), i18nc("@title:window", "Key Revoked")); } + + auto revokedKey = KeyCache::instance()->findByFingerprint(key.primaryFingerprint()); + if (haveKeyserverConfigured()) { + auto code = KMessageBox::questionTwoActions( + parentWidgetOrView(), + i18n("Do you want to publish the revoked certificate on the server?"), + i18nc("@title:dialog", "Publish on Server"), + KGuiItem(i18nc("@action:button Publish a certificate", "Publish"), QIcon::fromTheme(QStringLiteral("view-certificate-export-server"))), + KStandardGuiItem::close()); + if (code == KMessageBox::PrimaryAction) { + auto const cmd = new Commands::ExportOpenPGPCertsToServerCommand(revokedKey); + cmd->start(); + } + } + + auto code = KMessageBox::questionTwoActions( + parentWidgetOrView(), + xi18nc("@info", + "Do you want to export the revoked certificate?The exported certificate can then be sent to communication partners to inform " + "them about the revocation."), + i18nc("@title", "Export Certificate"), + KGuiItem(i18nc("@action:button Export a certificate", "Export"), QIcon::fromTheme(QStringLiteral("view-certificate-export"))), + KStandardGuiItem::close()); + if (code == KMessageBox::PrimaryAction) { + auto const cmd = new ExportCertificateCommand(revokedKey); + cmd->start(); + } finished(); } void RevokeKeyCommand::Private::showError(const Error &err) { error(xi18nc("@info", "An error occurred during the revocation:" "%1", Formatting::errorAsString(err)), i18nc("@title:window", "Revocation Failed")); } RevokeKeyCommand::RevokeKeyCommand(QAbstractItemView *v, KeyListController *c) : Command{v, new Private{this, c}} { } RevokeKeyCommand::RevokeKeyCommand(const GpgME::Key &key) : Command{key, new Private{this}} { } RevokeKeyCommand::~RevokeKeyCommand() = default; void RevokeKeyCommand::doStart() { d->start(); } void RevokeKeyCommand::doCancel() { d->cancel(); } #undef d #undef q #include "moc_revokekeycommand.cpp"