Page MenuHome GnuPG

No OneTemporary

diff --git a/src/dialogs/revokerswidget.cpp b/src/dialogs/revokerswidget.cpp
index ac26b3dce..3d928d93e 100644
--- a/src/dialogs/revokerswidget.cpp
+++ b/src/dialogs/revokerswidget.cpp
@@ -1,164 +1,164 @@
// SPDX-FileCopyrightText: 2024 g10 Code GmbH
// SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include "revokerswidget.h"
#include "commands/command.h"
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyList>
#include <Libkleo/TreeWidget>
#include <gpgme++/key.h>
#include <gpgme.h>
#include <KLocalizedString>
#include <KStandardAction>
#include <QClipboard>
#include <QGuiApplication>
#include <QKeyEvent>
#include <QMenu>
#include <QVBoxLayout>
using namespace Kleo;
class RevokersWidget::Private
{
public:
RevokersWidget *const q;
enum Column {
Fingerprint,
Name,
Email,
};
Private(RevokersWidget *qq)
: q(qq)
, ui{qq}
{
connect(ui.revokersTree, &QTreeWidget::doubleClicked, q, [this]() {
const auto index = ui.revokersTree->currentIndex();
if (!index.isValid()) {
return;
}
#if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
const auto fingerprint = QString::fromLatin1(key.revocationKey(ui.revokersTree->currentIndex().row()).fingerprint());
auto cmd = Command::commandForQuery(fingerprint);
- cmd->setParentWId(q->winId());
+ cmd->setParentWidget(q->window());
cmd->start();
#endif
});
}
public:
GpgME::Key key;
public:
struct UI {
QVBoxLayout *mainLayout;
TreeWidget *revokersTree;
UI(QWidget *widget)
{
mainLayout = new QVBoxLayout{widget};
mainLayout->setContentsMargins({});
revokersTree = new TreeWidget{widget};
revokersTree->setProperty("_breeze_force_frame", true);
revokersTree->setHeaderLabels({
i18nc("@title:column", "Fingerprint"),
i18nc("@title:column", "Name"),
i18nc("@title:column", "Email"),
});
revokersTree->setAccessibleName(i18nc("@label", "Revokers"));
revokersTree->setContextMenuPolicy(Qt::CustomContextMenu);
revokersTree->setRootIsDecorated(false);
mainLayout->addWidget(revokersTree);
connect(revokersTree, &QTreeWidget::customContextMenuRequested, widget, [widget, this](const auto &pos) {
auto menu = new QMenu;
menu->setAttribute(Qt::WA_DeleteOnClose, true);
menu->addAction(KStandardAction::copy(
widget,
[this]() {
QGuiApplication::clipboard()->setText(revokersTree->currentIndex().data(KeyList::ClipboardRole).toString());
},
widget));
menu->popup(widget->mapToGlobal(pos));
});
}
} ui;
};
RevokersWidget::RevokersWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
}
RevokersWidget::~RevokersWidget() = default;
void RevokersWidget::setKey(const GpgME::Key &key)
{
if (key.protocol() != GpgME::OpenPGP) {
return;
}
d->key = key;
d->ui.revokersTree->clear();
#if GPGME_VERSION_NUMBER >= 0x011800 // 1.24.0
for (size_t i = 0; i < key.numRevocationKeys(); i++) {
auto item = new QTreeWidgetItem;
auto revoker = key.revocationKey(i);
auto revokerKey = Kleo::KeyCache::instance()->findByFingerprint(revoker.fingerprint());
item->setData(Private::Fingerprint, Qt::DisplayRole, Formatting::prettyID(revoker.fingerprint()));
item->setData(Private::Fingerprint, Qt::AccessibleTextRole, Formatting::accessibleHexID(revoker.fingerprint()));
item->setData(Private::Fingerprint, KeyList::ClipboardRole, QString::fromLatin1(revoker.fingerprint()));
if (!revokerKey.isNull()) {
item->setData(Private::Name, Qt::DisplayRole, Formatting::prettyName(revokerKey));
item->setData(Private::Name, KeyList::ClipboardRole, Formatting::prettyName(revokerKey));
item->setData(Private::Email, Qt::DisplayRole, Formatting::prettyEMail(revokerKey));
item->setData(Private::Email, KeyList::ClipboardRole, Formatting::prettyEMail(revokerKey));
} else {
item->setData(Private::Name, Qt::DisplayRole, {});
item->setData(Private::Email, Qt::DisplayRole, {});
item->setData(Private::Name, Qt::AccessibleTextRole, i18nc("text for screen readers for an unknown name", "unknown name"));
item->setData(Private::Email, Qt::AccessibleTextRole, i18nc("text for screen readers for an unknown email", "unknown email"));
item->setData(Private::Name, KeyList::ClipboardRole, {});
item->setData(Private::Email, KeyList::ClipboardRole, {});
}
d->ui.revokersTree->addTopLevelItem(item);
}
#endif
QMetaObject::invokeMethod(
this,
[this]() {
if (!d->ui.revokersTree->restoreColumnLayout(QStringLiteral("RevokersWidget"))) {
for (int i = 0; i < d->ui.revokersTree->columnCount(); i++) {
d->ui.revokersTree->resizeColumnToContents(i);
}
}
},
Qt::QueuedConnection);
}
GpgME::Key RevokersWidget::key() const
{
return d->key;
}
void RevokersWidget::keyPressEvent(QKeyEvent *event)
{
if (event == QKeySequence::Copy) {
QGuiApplication::clipboard()->setText(d->ui.revokersTree->currentIndex().data(KeyList::ClipboardRole).toString());
}
}
#include "moc_revokerswidget.cpp"
diff --git a/src/dialogs/weboftrustwidget.cpp b/src/dialogs/weboftrustwidget.cpp
index dd147c63f..03b37818c 100644
--- a/src/dialogs/weboftrustwidget.cpp
+++ b/src/dialogs/weboftrustwidget.cpp
@@ -1,440 +1,440 @@
/*
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-FileCopyrightText: 2020 g10 Code GmbH
SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "weboftrustwidget.h"
#include "commands/certifycertificatecommand.h"
#include "commands/importcertificatefromkeyservercommand.h"
#include "commands/revokecertificationcommand.h"
#include "utils/tags.h"
#include <Libkleo/Formatting>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyHelpers>
#include <Libkleo/TreeView>
#include <Libkleo/UserIDListModel>
#include <Libkleo/UserIDListProxyModel>
#include <KLocalizedString>
#include <KMessageBox>
#include <KSeparator>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QLabel>
#include <QMenu>
#include <QPushButton>
#include <QVBoxLayout>
#include <QGpgME/KeyListJob>
#include <QGpgME/Protocol>
#include <gpgme++/key.h>
#include <gpgme++/keylistresult.h>
#include "kleopatra_debug.h"
using namespace Kleo;
namespace
{
void addActionButton(QLayout *buttonBox, QAction *action)
{
if (!action) {
return;
}
auto button = new QPushButton(buttonBox->parentWidget());
button->setText(action->text());
buttonBox->addWidget(button);
button->setEnabled(action->isEnabled());
QObject::connect(action, &QAction::changed, button, [action, button]() {
button->setEnabled(action->isEnabled());
});
QObject::connect(button, &QPushButton::clicked, action, &QAction::trigger);
}
}
class WebOfTrustWidget::Private
{
friend class ::Kleo::WebOfTrustWidget;
WebOfTrustWidget *const q;
private:
GpgME::Key key;
UserIDListModel certificationsModel;
UserIDListProxyModel proxyModel;
QGpgME::KeyListJob *keyListJob = nullptr;
TreeView *certificationsTV = nullptr;
QAction *detailsAction = nullptr;
QAction *certifyAction = nullptr;
QAction *revokeAction = nullptr;
QAction *fetchAction = nullptr;
QLabel *notAvailableLabel = nullptr;
QPushButton *moreButton = nullptr;
QCheckBox *showOnlyOwnCheck = nullptr;
public:
Private(WebOfTrustWidget *qq)
: q{qq}
{
certificationsModel.enableRemarks(Tags::tagsEnabled());
auto vLay = new QVBoxLayout(q);
vLay->setContentsMargins({});
proxyModel.setSourceModel(&certificationsModel);
certificationsTV = new TreeView{q};
certificationsTV->setAccessibleName(i18n("User IDs and certifications"));
certificationsTV->setModel(&proxyModel);
certificationsTV->setAllColumnsShowFocus(false);
certificationsTV->setSelectionMode(QAbstractItemView::SingleSelection);
if (!Tags::tagsEnabled()) {
certificationsTV->hideColumn(static_cast<int>(UserIDListModel::Column::Tags));
}
vLay->addWidget(certificationsTV);
notAvailableLabel = new QLabel(i18nc("@info", "Certifications are not available before the certificate is imported."));
notAvailableLabel->setAlignment(Qt::AlignHCenter);
notAvailableLabel->setVisible(false);
vLay->addWidget(notAvailableLabel);
detailsAction = new QAction{QIcon::fromTheme(QStringLiteral("dialog-information")), i18nc("@action", "Show Certificate Details"), q};
connect(detailsAction, &QAction::triggered, q, [this]() {
showCertificateDetails();
});
certifyAction = new QAction{QIcon::fromTheme(QStringLiteral("view-certificate-sign")), i18nc("@action", "Add Certification"), q};
connect(certifyAction, &QAction::triggered, q, [this]() {
addCertification();
});
if (Kleo::Commands::RevokeCertificationCommand::isSupported()) {
revokeAction = new QAction{QIcon::fromTheme(QStringLiteral("view-certificate-revoke")), i18nc("@action", "Revoke Certification"), q};
connect(revokeAction, &QAction::triggered, q, [this]() {
revokeCertification();
});
}
fetchAction = new QAction(QIcon::fromTheme(QStringLiteral("download")), i18nc("@action:button", "Fetch Missing Keys"));
fetchAction->setToolTip(i18nc("@info:tooltip", "Look up and import all keys that were used to certify the user IDs of this key"));
connect(fetchAction, &QAction::triggered, q, [this]() {
fetchMissingKeys();
});
auto bbox = new QHBoxLayout;
addActionButton(bbox, certifyAction);
addActionButton(bbox, revokeAction);
moreButton = new QPushButton(QIcon::fromTheme(QStringLiteral("application-menu")), {});
moreButton->setToolTip(i18nc("@info:tooltip", "Show more options"));
bbox->addWidget(moreButton);
connect(moreButton, &QPushButton::clicked, q, [this]() {
auto menu = new QMenu(q);
menu->addAction(detailsAction);
menu->addAction(fetchAction);
menu->popup(moreButton->mapToGlobal(QPoint()));
});
showOnlyOwnCheck = new QCheckBox(i18nc("label:checkbox", "Show only my own certifications"));
bbox->addWidget(showOnlyOwnCheck);
connect(showOnlyOwnCheck, &QCheckBox::toggled, &proxyModel, &UserIDListProxyModel::setShowOnlyOwnCertifications);
bbox->addStretch(1);
vLay->addLayout(bbox);
connect(certificationsTV, &QAbstractItemView::doubleClicked, q, [this]() {
certificationDblClicked();
});
certificationsTV->setContextMenuPolicy(Qt::CustomContextMenu);
connect(certificationsTV, &QWidget::customContextMenuRequested, q, [this](const QPoint &p) {
contextMenuRequested(p);
});
connect(certificationsTV->selectionModel(), &QItemSelectionModel::currentRowChanged, q, [this]() {
updateActions();
});
updateActions();
}
GpgME::UserID selectedUserID()
{
return proxyModel.userID(certificationsTV->currentIndex());
}
GpgME::UserID::Signature selectedCertification()
{
return proxyModel.signature(certificationsTV->currentIndex());
}
void certificationDblClicked()
{
showCertificateDetails();
}
void showCertificateDetails()
{
const auto signature = selectedCertification();
if (signature.isNull()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "- no certification selected";
return;
}
auto cmd = Command::commandForQuery(QString::fromUtf8(signature.signerKeyID()));
- cmd->setParentWId(q->winId());
+ cmd->setParentWidget(q->window());
cmd->start();
}
void addCertification()
{
auto userID = selectedUserID();
if (userID.isNull()) {
userID = selectedCertification().parent();
}
if (userID.isNull()) {
qCDebug(KLEOPATRA_LOG) << __func__ << "- no user ID or certification selected";
return;
}
auto cmd = new Kleo::Commands::CertifyCertificateCommand(userID);
cmd->setParentWidget(q);
certificationsTV->setEnabled(false);
connect(cmd, &Kleo::Commands::CertifyCertificateCommand::finished, q, [this]() {
certificationsTV->setEnabled(true);
// Trigger an update when done
q->setKey(key);
});
cmd->start();
}
void revokeCertification()
{
Command *cmd = nullptr;
if (const auto signature = selectedCertification(); !signature.isNull()) {
cmd = new Kleo::Commands::RevokeCertificationCommand(signature);
} else if (const auto userID = selectedUserID(); !userID.isNull()) {
cmd = new Kleo::Commands::RevokeCertificationCommand(userID);
} else {
qCDebug(KLEOPATRA_LOG) << __func__ << "- no user ID or certification selected";
return;
}
cmd->setParentWidget(q);
certificationsTV->setEnabled(false);
connect(cmd, &Kleo::Commands::RevokeCertificationCommand::finished, q, [this]() {
certificationsTV->setEnabled(true);
// Trigger an update when done
q->setKey(key);
});
cmd->start();
}
void addActionsForUserID(QMenu *menu)
{
menu->addAction(certifyAction);
if (revokeAction) {
menu->addAction(revokeAction);
}
}
void addActionsForSignature(QMenu *menu)
{
menu->addAction(detailsAction);
menu->addAction(certifyAction);
if (revokeAction) {
menu->addAction(revokeAction);
if (!revokeAction->isEnabled()) {
menu->setToolTipsVisible(true);
}
}
}
void updateActions()
{
const auto userCanSignUserIDs = userHasCertificationKey();
const auto keyCanBeCertified = Kleo::canBeCertified(key);
const auto userID = selectedUserID();
const auto signature = selectedCertification();
detailsAction->setEnabled(!signature.isNull());
certifyAction->setEnabled(keyCanBeCertified && userCanSignUserIDs && (!userID.isNull() || !signature.isNull()));
if (revokeAction) {
revokeAction->setToolTip({});
if (!signature.isNull()) {
const auto revocationFeasibility = userCanRevokeCertification(signature);
revokeAction->setEnabled(revocationFeasibility == CertificationCanBeRevoked);
switch (revocationFeasibility) {
case CertificationCanBeRevoked:
break;
case CertificationNotMadeWithOwnKey:
revokeAction->setToolTip(
i18n("You cannot revoke this certification because it wasn't made with one of your keys (or the required secret key is missing)."));
break;
case CertificationIsSelfSignature:
revokeAction->setToolTip(i18nc("@info:tooltip", "Revocation of self-certifications is currently not possible."));
break;
case CertificationIsRevocation:
revokeAction->setToolTip(
i18nc("@info:tooltip", "You cannot revoke this revocation certification. (But you can re-certify the corresponding user ID.)"));
break;
case CertificationIsExpired:
revokeAction->setToolTip(i18nc("@info:tooltip", "You cannot revoke this expired certification."));
break;
case CertificationIsInvalid:
revokeAction->setToolTip(i18nc("@info:tooltip", "You cannot revoke this invalid certification."));
break;
case CertificationKeyNotAvailable:
revokeAction->setToolTip(i18nc("@info:tooltip", "You cannot revoke this certification because the required secret key is not available."));
break;
};
} else if (!userID.isNull()) {
const bool canRevokeCertification = userCanRevokeCertifications(userID);
revokeAction->setEnabled(canRevokeCertification);
if (!canRevokeCertification) {
revokeAction->setToolTip(
i18n("You cannot revoke any of the certifications of this user ID. Select any of the certifications for details."));
}
} else {
revokeAction->setEnabled(false);
}
}
}
void contextMenuRequested(const QPoint &p)
{
const auto userID = proxyModel.userID(certificationsTV->indexAt(p));
const auto signature = proxyModel.signature(certificationsTV->indexAt(p));
if (userID.isNull() && signature.isNull()) {
return;
}
auto menu = new QMenu(q);
if (!userID.isNull()) {
addActionsForUserID(menu);
} else if (!signature.isNull()) {
addActionsForSignature(menu);
}
connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater);
menu->popup(certificationsTV->viewport()->mapToGlobal(p));
}
void startSignatureListing()
{
if (keyListJob) {
return;
}
QGpgME::KeyListJob *const job = QGpgME::openpgp()->keyListJob(/*remote*/ false, /*includeSigs*/ true, /*validate*/ true);
if (!job) {
return;
}
if (Tags::tagsEnabled()) {
job->addMode(GpgME::SignatureNotations);
}
connect(job, &QGpgME::KeyListJob::result, q, &WebOfTrustWidget::signatureListingDone);
connect(job, &QGpgME::KeyListJob::nextKey, q, &WebOfTrustWidget::signatureListingNextKey);
job->start(QStringList(QString::fromLatin1(key.primaryFingerprint())));
keyListJob = job;
}
void fetchMissingKeys()
{
if (q->key().isNull()) {
return;
}
const auto missingSignerKeyIds = Kleo::getMissingSignerKeyIds(q->key().userIDs());
auto cmd = new Kleo::ImportCertificateFromKeyserverCommand{QStringList{std::begin(missingSignerKeyIds), std::end(missingSignerKeyIds)}};
cmd->setParentWidget(q);
fetchAction->setEnabled(false);
connect(cmd, &Kleo::ImportCertificateFromKeyserverCommand::finished, q, [this]() {
// Trigger an update when done
q->setKey(q->key());
fetchAction->setEnabled(true);
});
cmd->start();
}
};
WebOfTrustWidget::WebOfTrustWidget(QWidget *parent)
: QWidget{parent}
, d{std::make_unique<Private>(this)}
{
}
WebOfTrustWidget::~WebOfTrustWidget() = default;
QAction *WebOfTrustWidget::detailsAction() const
{
return d->detailsAction;
}
QAction *WebOfTrustWidget::certifyAction() const
{
return d->certifyAction;
}
QAction *WebOfTrustWidget::revokeAction() const
{
return d->revokeAction;
}
GpgME::Key WebOfTrustWidget::key() const
{
return d->key;
}
void WebOfTrustWidget::setKey(const GpgME::Key &key)
{
if (key.protocol() != GpgME::OpenPGP) {
qCDebug(KLEOPATRA_LOG) << "List of Certifications is only supported for OpenPGP keys";
return;
}
if (isRemoteKey(key)) {
d->certificationsTV->setVisible(false);
d->notAvailableLabel->setVisible(true);
d->moreButton->setEnabled(false);
}
d->key = key;
d->certificationsModel.setKey(key);
d->updateActions();
d->certificationsTV->expandAll();
d->certificationsTV->header()->resizeSections(QHeaderView::ResizeToContents);
d->startSignatureListing();
d->certificationsTV->restoreColumnLayout(QStringLiteral("WebOfTrustWidget"));
for (int i = 0; i < d->certificationsModel.columnCount(); i++) {
d->certificationsTV->resizeColumnToContents(i);
}
d->fetchAction->setEnabled(!key.isBad());
}
void WebOfTrustWidget::signatureListingNextKey(const GpgME::Key &key)
{
GpgME::Key merged = key;
merged.mergeWith(d->key);
setKey(merged);
}
void WebOfTrustWidget::signatureListingDone(const GpgME::KeyListResult &result)
{
if (result.error()) {
KMessageBox::information(this,
xi18nc("@info",
"<para>An error occurred while loading the certifications: "
"<message>%1</message></para>",
Formatting::errorAsString(result.error())),
i18nc("@title", "Certifications Loading Failed"));
}
d->keyListJob = nullptr;
}
#include "moc_weboftrustwidget.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Fri, Aug 29, 7:59 AM (1 d, 9 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
75/3a/c2789e6fccda7e62a198cc09ff0b

Event Timeline