Page MenuHome GnuPG

newopenpgpcertificatecommand.cpp
No OneTemporary

newopenpgpcertificatecommand.cpp

/* -*- mode: c++; c-basic-offset:4 -*-
commands/newopenpgpcertificatecommand.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2008 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "newopenpgpcertificatecommand.h"
#include "command_p.h"
#include "dialogs/newopenpgpcertificatedetailsdialog.h"
#include "utils/emptypassphraseprovider.h"
#include "utils/keyparameters.h"
#include "utils/userinfo.h"
#include <settings.h>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSharedConfig>
#include <QGpgME/KeyGenerationJob>
#include <QGpgME/Protocol>
#include <QProgressDialog>
#include <gpgme++/context.h>
#include <gpgme++/keygenerationresult.h>
#include <kleopatra_debug.h>
using namespace Kleo;
using namespace GpgME;
class NewOpenPGPCertificateCommand::Private : public Command::Private
{
friend class ::Kleo::NewOpenPGPCertificateCommand;
NewOpenPGPCertificateCommand *q_func() const
{
return static_cast<NewOpenPGPCertificateCommand *>(q);
}
public:
explicit Private(NewOpenPGPCertificateCommand *qq, KeyListController *c)
: Command::Private{qq, c}
{
}
void getCertificateDetails();
void createCertificate();
void showResult(const KeyGenerationResult &result);
void showErrorDialog(const KeyGenerationResult &result);
private:
KeyParameters keyParameters;
bool protectKeyWithPassword = false;
EmptyPassphraseProvider emptyPassphraseProvider;
QPointer<NewOpenPGPCertificateDetailsDialog> detailsDialog;
QPointer<QGpgME::Job> job;
QPointer<QProgressDialog> progressDialog;
};
NewOpenPGPCertificateCommand::Private *NewOpenPGPCertificateCommand::d_func()
{
return static_cast<Private *>(d.get());
}
const NewOpenPGPCertificateCommand::Private *NewOpenPGPCertificateCommand::d_func() const
{
return static_cast<const Private *>(d.get());
}
#define d d_func()
#define q q_func()
void NewOpenPGPCertificateCommand::Private::getCertificateDetails()
{
detailsDialog = new NewOpenPGPCertificateDetailsDialog;
detailsDialog->setAttribute(Qt::WA_DeleteOnClose);
applyWindowID(detailsDialog);
if (keyParameters.protocol() == KeyParameters::NoProtocol) {
const auto settings = Kleo::Settings{};
const KConfigGroup config{KSharedConfig::openConfig(), "CertificateCreationWizard"};
// prefer the last used name and email address over the values retrieved from the system
detailsDialog->setName(config.readEntry("NAME", QString{}));
if (detailsDialog->name().isEmpty() && settings.prefillName()) {
detailsDialog->setName(userFullName());
}
detailsDialog->setEmail(config.readEntry("EMAIL", QString{}));
if (detailsDialog->email().isEmpty() && settings.prefillEmail()) {
detailsDialog->setEmail(userEmailAddress());
}
} else {
detailsDialog->setKeyParameters(keyParameters);
detailsDialog->setProtectKeyWithPassword(protectKeyWithPassword);
}
connect(detailsDialog, &QDialog::accepted, q, [this]() {
keyParameters = detailsDialog->keyParameters();
protectKeyWithPassword = detailsDialog->protectKeyWithPassword();
QMetaObject::invokeMethod(
q,
[this] {
createCertificate();
},
Qt::QueuedConnection);
});
connect(detailsDialog, &QDialog::rejected, q, [this]() {
canceled();
});
detailsDialog->show();
}
void NewOpenPGPCertificateCommand::Private::createCertificate()
{
Q_ASSERT(keyParameters.protocol() == KeyParameters::OpenPGP);
auto keyGenJob = QGpgME::openpgp()->keyGenerationJob();
if (!keyGenJob) {
finished();
return;
}
if (!protectKeyWithPassword) {
auto ctx = QGpgME::Job::context(keyGenJob);
ctx->setPassphraseProvider(&emptyPassphraseProvider);
ctx->setPinentryMode(Context::PinentryLoopback);
}
connect(keyGenJob, &QGpgME::KeyGenerationJob::result, q, [this](const KeyGenerationResult &result) {
QMetaObject::invokeMethod(
q,
[this, result] {
showResult(result);
},
Qt::QueuedConnection);
});
if (const Error err = keyGenJob->start(keyParameters.toString())) {
error(i18n("Could not start key pair creation: %1", Formatting::errorAsString(err)));
finished();
return;
} else {
job = keyGenJob;
}
progressDialog = new QProgressDialog;
progressDialog->setAttribute(Qt::WA_DeleteOnClose);
applyWindowID(progressDialog);
progressDialog->setModal(true);
progressDialog->setWindowTitle(i18nc("@title", "Creating Key Pair..."));
progressDialog->setLabelText(i18n("The process of creating a key requires large amounts of random numbers. This may require several minutes..."));
progressDialog->setRange(0, 0);
connect(progressDialog, &QProgressDialog::canceled, job, &QGpgME::Job::slotCancel);
connect(job, &QGpgME::Job::done, q, [this]() {
if (progressDialog) {
progressDialog->accept();
}
});
progressDialog->show();
}
void NewOpenPGPCertificateCommand::Private::showResult(const KeyGenerationResult &result)
{
if (result.error().isCanceled()) {
finished();
return;
}
// Ensure that we have the key in the cache
Key key;
if (!result.error().code() && result.fingerprint()) {
std::unique_ptr<Context> ctx{Context::createForProtocol(OpenPGP)};
if (ctx) {
Error err;
key = ctx->key(result.fingerprint(), err, /*secret=*/true);
if (!key.isNull()) {
KeyCache::mutableInstance()->insert(key);
}
}
}
if (!key.isNull()) {
success(
xi18n("<para>A new OpenPGP certificate was created successfully.</para>"
"<para>Fingerprint of the new certificate: %1</para>",
Formatting::prettyID(key.primaryFingerprint())));
finished();
} else {
showErrorDialog(result);
}
}
void NewOpenPGPCertificateCommand::Private::showErrorDialog(const KeyGenerationResult &result)
{
QString text;
if (result.error() || !result.fingerprint()) {
text = xi18n(
"<para>The creation of a new OpenPGP certificate failed.</para>"
"<para>Error: <message>%1</message></para>",
Formatting::errorAsString(result.error()));
} else {
// no error and we have a fingerprint, but there was no corresponding key in the key ring
text = xi18n(
"<para>A new OpenPGP certificate was created successfully, but it has not been found in the key ring.</para>"
"<para>Fingerprint of the new certificate:<nl/>%1</para>",
Formatting::prettyID(result.fingerprint()));
}
auto dialog = new QDialog;
applyWindowID(dialog);
dialog->setWindowTitle(i18nc("@title:window", "Error"));
auto buttonBox = new QDialogButtonBox{QDialogButtonBox::Retry | QDialogButtonBox::Ok, dialog};
const auto buttonCode = KMessageBox::createKMessageBox(dialog, buttonBox, QMessageBox::Critical, text, {}, {}, nullptr, {});
if (buttonCode == QDialogButtonBox::Retry) {
QMetaObject::invokeMethod(
q,
[this]() {
getCertificateDetails();
},
Qt::QueuedConnection);
} else {
finished();
}
}
NewOpenPGPCertificateCommand::NewOpenPGPCertificateCommand()
: NewOpenPGPCertificateCommand(nullptr, nullptr)
{
}
NewOpenPGPCertificateCommand::NewOpenPGPCertificateCommand(QAbstractItemView *v, KeyListController *c)
: Command(v, new Private(this, c))
{
}
NewOpenPGPCertificateCommand::~NewOpenPGPCertificateCommand() = default;
void NewOpenPGPCertificateCommand::doStart()
{
d->getCertificateDetails();
}
void NewOpenPGPCertificateCommand::doCancel()
{
if (d->detailsDialog) {
d->detailsDialog->close();
}
if (d->job) {
d->job->slotCancel();
}
}
#undef d
#undef q

File Metadata

Mime Type
text/x-c++
Expires
Thu, Dec 11, 12:55 AM (2 h, 26 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
4a/54/868afdf557687fe0eb104727e4e0

Event Timeline