Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F31766627
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 c950a1de7..b7fae5644 100644
--- a/src/commands/newopenpgpcertificatecommand.cpp
+++ b/src/commands/newopenpgpcertificatecommand.cpp
@@ -1,277 +1,312 @@
/*
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 <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 handleKeyGenerationResult(const KeyGenerationResult &result);
void showErrorDialog(const KeyGenerationResult &result);
private:
KeyParameters keyParameters;
bool protectKeyWithPassword = false;
+ bool teamKey = false;
EmptyPassphraseProvider emptyPassphraseProvider;
QPointer<OpenPGPCertificateCreationDialog> detailsDialog;
QPointer<QGpgME::Job> job;
QPointer<QProgressDialog> progressDialog;
std::shared_ptr<KeyCacheAutoRefreshSuspension> keyCacheAutoRefreshSuspension;
+ QString algoString;
};
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);
+ detailsDialog->showTeamKeyOption(true);
applyWindowID(detailsDialog);
if (keyParameters.protocol() == KeyParameters::NoProtocol) {
const auto settings = Kleo::Settings{};
const KConfigGroup config{KSharedConfig::openConfig(), QLatin1StringView("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();
+ teamKey = detailsDialog->isTeamKey();
+ algoString = detailsDialog->algoString();
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();
connect(keyGenJob, &QGpgME::KeyGenerationJob::result, q, [this](const KeyGenerationResult &result) {
QMetaObject::invokeMethod(
q,
[this, result] {
- showResult(result);
+ handleKeyGenerationResult(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)
+void NewOpenPGPCertificateCommand::Private::handleKeyGenerationResult(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(KeyListMode::Validate | KeyListMode::Signatures | KeyListMode::SignatureNotations);
key = ctx->key(result.fingerprint(), err, /*secret=*/true);
if (!key.isNull()) {
KeyCache::mutableInstance()->insert(key);
}
}
}
+ if (key.isNull()) {
+ showErrorDialog(result);
+ }
+
keyCacheAutoRefreshSuspension.reset();
- if (!key.isNull()) {
+ if (teamKey) {
+ auto quickJob = std::unique_ptr<QGpgME::QuickJob>(QGpgME::openpgp()->quickJob());
+ auto flags = Context::CreationFlags::CreateSign;
+ if (!protectKeyWithPassword) {
+ flags |= GpgME::Context::CreationFlags::CreateNoPassword;
+ }
+ connect(quickJob.get(), &QGpgME::QuickJob::result, q, [this, result, key](const auto &err) {
+ if (err) {
+ error(i18nc("@info", "Failed to create signing subkey: %1", Formatting::errorAsString(err)));
+ return;
+ }
+
+ if (err.isCanceled()) {
+ return;
+ }
+ 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();
+ });
+ auto err = quickJob->startAddSubkey(key, algoString.toLatin1(), {}, flags);
+ if (err) {
+ error(i18nc("@info", "Failed to create signing subkey: %1", Formatting::errorAsString(err)));
+ return;
+ }
+ auto _ = quickJob.release();
+ } else {
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();
}
}
#undef d
#undef q
#include "moc_newopenpgpcertificatecommand.cpp"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Nov 6, 3:15 PM (22 h, 18 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
87/cd/17b832e1dd5e4159d2bf64889719
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment