Commit 4fe2bb57 authored by Ingo Klöcker's avatar Ingo Klöcker
Browse files

Add support for changing the expiry of a subkey

With latest GPGME this allows users to change the expiry of subkeys
with Kleopatra.

GnuPG-bug-id: 4717
parent 1aa9fe90
Pipeline #30329 passed with stage
in 12 minutes and 11 seconds
......@@ -50,6 +50,12 @@
#include <QDateTime>
#include <QDebug>
#include <gpgme++/gpgmepp_version.h>
#if GPGMEPP_VERSION >= 0x10E01 // 1.14.1
# define CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
#endif
using namespace Kleo;
using namespace Kleo::Commands;
......@@ -83,6 +89,7 @@ private:
private:
GpgME::Key key;
GpgME::Subkey subkey;
QPointer<ExpiryDialog> dialog;
QPointer<ChangeExpiryJob> job;
};
......@@ -141,9 +148,13 @@ ChangeExpiryCommand::~ChangeExpiryCommand()
qCDebug(KLEOPATRA_LOG);
}
void ChangeExpiryCommand::doStart()
void ChangeExpiryCommand::setSubkey(const GpgME::Subkey &subkey)
{
d->subkey = subkey;
}
void ChangeExpiryCommand::doStart()
{
const std::vector<Key> keys = d->keys();
if (keys.size() != 1 ||
keys.front().protocol() != GpgME::OpenPGP ||
......@@ -155,10 +166,20 @@ void ChangeExpiryCommand::doStart()
d->key = keys.front();
if (!d->subkey.isNull() &&
d->subkey.parent().primaryFingerprint() != d->key.primaryFingerprint()) {
qDebug() << "Invalid subkey" << d->subkey.fingerprint()
<< ": Not a subkey of key" << d->key.primaryFingerprint();
d->finished();
return;
}
const Subkey subkey = !d->subkey.isNull() ? d->subkey : d->key.subkey(0);
d->ensureDialogCreated();
Q_ASSERT(d->dialog);
const Subkey subkey = d->key.subkey(0);
d->dialog->setDateOfExpiry(subkey.neverExpires() ? QDate() : QDateTime::fromSecsSinceEpoch(d->key.subkey(0).expirationTime()).date());
d->dialog->setDateOfExpiry(subkey.neverExpires() ? QDate() :
QDateTime::fromSecsSinceEpoch(subkey.expirationTime()).date());
d->dialog->show();
}
......@@ -167,7 +188,7 @@ void ChangeExpiryCommand::Private::slotDialogAccepted()
{
Q_ASSERT(dialog);
static const QTime END_OF_DAY(23, 59, 59); // not used, so as good as any
static const QTime END_OF_DAY(23, 59, 59);
const QDateTime expiry(dialog->dateOfExpiry(), END_OF_DAY);
......@@ -176,7 +197,16 @@ void ChangeExpiryCommand::Private::slotDialogAccepted()
createJob();
Q_ASSERT(job);
std::vector<Subkey> subkeys;
if (!subkey.isNull()) {
subkeys.push_back(subkey);
}
#ifdef CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
if (const Error err = job->start(key, expiry, subkeys)) {
#else
if (const Error err = job->start(key, expiry)) {
#endif
showErrorDialog(err);
finished();
}
......
......@@ -35,6 +35,11 @@
#include <commands/command.h>
namespace GpgME
{
class Subkey;
}
namespace Kleo
{
namespace Commands
......@@ -54,6 +59,8 @@ public:
return OnlyOneKey | MustBeOpenPGP | NeedSecretKey;
}
void setSubkey(const GpgME::Subkey &subkey);
private:
void doStart() override;
void doCancel() override;
......
......@@ -22,6 +22,7 @@
#include "smartcard/readerstatus.h"
#include "commands/changeexpirycommand.h"
#include "commands/keytocardcommand.h"
#include "commands/importpaperkeycommand.h"
#include "exportdialog.h"
......@@ -40,6 +41,9 @@
#if GPGMEPP_VERSION >= 0x10E00 // 1.14.0
# define GPGME_HAS_EXPORT_FLAGS
#endif
#if GPGMEPP_VERSION >= 0x10E01 // 1.14.1
# define CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
#endif
#include <Libkleo/Formatting>
......@@ -79,6 +83,30 @@ void SubKeysWidget::Private::tableContextMenuRequested(const QPoint &p)
bool hasActions = false;
#ifdef CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
if (subkey.parent().protocol() == GpgME::OpenPGP && subkey.parent().hasSecret()) {
hasActions = true;
menu->addAction(i18n("Change Expiry Date..."), q,
[this, subkey]() {
auto cmd = new Kleo::Commands::ChangeExpiryCommand(subkey.parent());
if (subkey.keyID() != key.keyID()) {
// do not set the primary key as subkey
cmd->setSubkey(subkey);
}
ui.subkeysTree->setEnabled(false);
connect(cmd, &Kleo::Commands::ChangeExpiryCommand::finished,
q, [this]() {
ui.subkeysTree->setEnabled(true);
key.update();
q->setKey(key);
});
cmd->setParentWidget(q);
cmd->start();
}
);
}
#endif // CHANGEEXPIRYJOB_SUPPORTS_SUBKEYS
#ifdef GPGME_HAS_EXPORT_FLAGS
if (subkey.parent().protocol() == GpgME::OpenPGP && subkey.canAuthenticate()) {
hasActions = true;
......@@ -148,6 +176,11 @@ void SubKeysWidget::setKey(const GpgME::Key &key)
{
d->key = key;
const auto currentItem = d->ui.subkeysTree->currentItem();
const QByteArray selectedKeyFingerprint = currentItem ?
QByteArray(currentItem->data(0, Qt::UserRole).value<GpgME::Subkey>().fingerprint()) : QByteArray();
d->ui.subkeysTree->clear();
for (const auto &subkey : key.subkeys()) {
auto item = new QTreeWidgetItem();
item->setData(0, Qt::DisplayRole, Formatting::prettyID(subkey.keyID()));
......@@ -168,6 +201,9 @@ void SubKeysWidget::setKey(const GpgME::Key &key)
item->setData(6, Qt::DisplayRole, Kleo::Formatting::usageString(subkey));
item->setData(7, Qt::DisplayRole, subkey.keyID() == key.keyID() ? QStringLiteral("✓") : QString());
d->ui.subkeysTree->addTopLevelItem(item);
if (subkey.fingerprint() == selectedKeyFingerprint) {
d->ui.subkeysTree->setCurrentItem(item);
}
}
const auto subkey = key.subkey(0);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment