Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F29856963
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
11 KB
Subscribers
None
View Options
diff --git a/src/commands/newopenpgpcertificatecommand.cpp b/src/commands/newopenpgpcertificatecommand.cpp
index 208068923..517c88bdf 100644
--- a/src/commands/newopenpgpcertificatecommand.cpp
+++ b/src/commands/newopenpgpcertificatecommand.cpp
@@ -1,325 +1,327 @@
/*
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 "kleopatraapplication.h"
#include "utils/emptypassphraseprovider.h"
#include "utils/userinfo.h"
#include <qgpgme/quickjob.h>
#include <settings.h>
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyParameters>
#include <Libkleo/OpenPGPCertificateCreationDialog>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSharedConfig>
#include <QGpgME/KeyGenerationJob>
#include <QGpgME/Protocol>
#include <QGpgME/QuickJob>
#include <QProgressDialog>
#include <QSettings>
#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;
bool isTeamKey = false;
EmptyPassphraseProvider emptyPassphraseProvider;
QPointer<OpenPGPCertificateCreationDialog> detailsDialog;
QPointer<QGpgME::Job> job;
QPointer<QProgressDialog> progressDialog;
std::shared_ptr<KeyCacheAutoRefreshSuspension> keyCacheAutoRefreshSuspension;
};
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 OpenPGPCertificateCreationDialog;
detailsDialog->setAttribute(Qt::WA_DeleteOnClose);
applyWindowID(detailsDialog);
if (isTeamKey) {
detailsDialog->setWindowTitle(i18nc("title:window", "Create OpenPGP Team Certificate"));
detailsDialog->setInfoText(
i18nc("@info", "Enter a name and/or an email address to use for the certificate. The certificate will be set up for shared usage in a team."));
+ detailsDialog->setEmailLabel(i18nc("@label", "Team email address"));
+ detailsDialog->setNameLabel(i18nc("@label", "Team name"));
}
if (keyParameters.protocol() == KeyParameters::NoProtocol) {
const auto settings = Kleo::Settings{};
const KConfigGroup config{KSharedConfig::openConfig(), QLatin1StringView("CertificateCreationWizard")};
if (!isTeamKey) {
// 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);
}
auto settings = KleopatraApplication::instance()->distributionSettings();
if (settings) {
keyParameters.setComment(settings->value(QStringLiteral("uidcomment"), {}).toString());
}
keyCacheAutoRefreshSuspension = KeyCache::mutableInstance()->suspendAutoRefresh();
auto usage = keyParameters.keyUsage();
usage.setIsGroupKey(isTeamKey);
usage.setCanSign(!isTeamKey);
keyParameters.setKeyUsage(usage);
connect(keyGenJob, &QGpgME::KeyGenerationJob::result, q, [this](const KeyGenerationResult &result) {
QMetaObject::invokeMethod(
q,
[this, result] {
if (isTeamKey) {
connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, q, [result, this]() {
auto key = KeyCache::instance()->findByFingerprint(result.fingerprint());
if (key.isNull()) {
return;
}
auto quickJob = QGpgME::openpgp()->quickJob();
auto err = quickJob->startAddSubkey(key, QByteArrayLiteral("rsa3072") /*TODO*/, {}, Context::CreationFlags::CreateSign);
disconnect(KeyCache::instance().get(), nullptr, q, nullptr);
if (err) {
error(i18nc("@info", "Failed to create encryption subkey: %1", Formatting::errorAsString(err)));
return;
}
connect(quickJob, &QGpgME::QuickJob::result, q, [this, result](const auto &err) {
if (err) {
error(i18nc("@info", "Failed to create encryption subkey: %1", Formatting::errorAsString(err)));
return;
}
if (err.isCanceled()) {
return;
}
showResult(result);
});
});
} else {
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;
ctx->addKeyListMode(GpgME::Validate);
key = ctx->key(result.fingerprint(), err, /*secret=*/true);
if (!key.isNull()) {
KeyCache::mutableInstance()->insert(key);
}
}
}
keyCacheAutoRefreshSuspension.reset();
if (!key.isNull()) {
success(xi18nc("@info",
"<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 = xi18nc("@info",
"<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 = xi18nc("@info",
"<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();
}
}
void NewOpenPGPCertificateCommand::setIsTeamKey(bool isTeamKey)
{
d->isTeamKey = isTeamKey;
}
#undef d
#undef q
#include "moc_newopenpgpcertificatecommand.cpp"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Oct 16, 4:50 AM (1 d, 11 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
93/b1/eb2bc6c977b3bcee3180f879c748
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment