Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F18824915
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
17 KB
Subscribers
None
View Options
diff --git a/src/dialogs/subkeyswidget.cpp b/src/dialogs/subkeyswidget.cpp
index dd4d9f116..26f1c8509 100644
--- a/src/dialogs/subkeyswidget.cpp
+++ b/src/dialogs/subkeyswidget.cpp
@@ -1,322 +1,323 @@
/*
dialogs/subkeyswidget.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2016 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2017 Bundesamt für Sicherheit in der Informationstechnik
SPDX-FileContributor: Intevation GmbH
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 "subkeyswidget.h"
#include "commands/changeexpirycommand.h"
#ifdef QGPGME_SUPPORTS_SECRET_SUBKEY_EXPORT
#include "commands/exportsecretsubkeycommand.h"
#endif
#include "commands/keytocardcommand.h"
#include "commands/importpaperkeycommand.h"
#include "exportdialog.h"
#include <Libkleo/Formatting>
#include <Libkleo/NavigatableTreeWidget>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QMenu>
#include <QPushButton>
#include <QTreeWidgetItem>
#include <QVBoxLayout>
#include <gpgme++/context.h>
#include <gpgme++/key.h>
Q_DECLARE_METATYPE(GpgME::Subkey)
using namespace Kleo;
using namespace Kleo::Commands;
class SubKeysWidget::Private
{
SubKeysWidget *const q;
public:
Private(SubKeysWidget *qq)
: q{qq}
, ui{qq}
{
ui.subkeysTree->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui.subkeysTree, &QAbstractItemView::customContextMenuRequested,
q, [this](const QPoint &p) { tableContextMenuRequested(p); });
}
private:
void tableContextMenuRequested(const QPoint &p);
public:
GpgME::Key key;
public:
struct UI {
QVBoxLayout *mainLayout;
NavigatableTreeWidget *subkeysTree;
UI(QWidget *widget)
{
mainLayout = new QVBoxLayout{widget};
mainLayout->setContentsMargins(0, 0, 0, 0);
auto subkeysTreeLabel = new QLabel{i18nc("@label", "Subkeys:"), widget};
mainLayout->addWidget(subkeysTreeLabel);
subkeysTree = new NavigatableTreeWidget{widget};
subkeysTreeLabel->setBuddy(subkeysTree);
subkeysTree->setAccessibleName(i18nc("@label", "Subkeys"));
subkeysTree->setRootIsDecorated(false);
subkeysTree->setHeaderLabels({
i18nc("@title:column", "ID"),
i18nc("@title:column", "Type"),
i18nc("@title:column", "Valid From"),
i18nc("@title:column", "Valid Until"),
i18nc("@title:column", "Status"),
i18nc("@title:column", "Strength"),
i18nc("@title:column", "Usage"),
i18nc("@title:column", "Primary"),
i18nc("@title:column", "Storage"),
});
mainLayout->addWidget(subkeysTree);
}
} ui;
};
void SubKeysWidget::Private::tableContextMenuRequested(const QPoint &p)
{
auto item = ui.subkeysTree->itemAt(p);
if (!item) {
return;
}
const auto subkey = item->data(0, Qt::UserRole).value<GpgME::Subkey>();
const bool isOpenPGPKey = subkey.parent().protocol() == GpgME::OpenPGP;
auto menu = new QMenu(q);
connect(menu, &QMenu::aboutToHide, menu, &QObject::deleteLater);
bool hasActions = false;
if (isOpenPGPKey && subkey.parent().hasSecret()) {
hasActions = true;
menu->addAction(i18n("Change End of Validity Period..."), q,
[this, subkey]() {
auto cmd = new ChangeExpiryCommand(subkey.parent());
cmd->setSubkey(subkey);
ui.subkeysTree->setEnabled(false);
connect(cmd, &ChangeExpiryCommand::finished,
q, [this]() {
ui.subkeysTree->setEnabled(true);
key.update();
q->setKey(key);
});
cmd->setParentWidget(q);
cmd->start();
}
);
}
if (isOpenPGPKey && subkey.canAuthenticate()) {
hasActions = true;
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-export")),
i18n("Export OpenSSH key"),
q, [this, subkey]() {
QScopedPointer<ExportDialog> dlg(new ExportDialog(q));
dlg->setKey(subkey, static_cast<unsigned int> (GpgME::Context::ExportSSH));
dlg->exec();
});
}
if (!subkey.isSecret()) {
hasActions = true;
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-import")),
i18n("Restore printed backup"),
q, [this, subkey] () {
auto cmd = new ImportPaperKeyCommand(subkey.parent());
ui.subkeysTree->setEnabled(false);
connect(cmd, &ImportPaperKeyCommand::finished,
q, [this]() { ui.subkeysTree->setEnabled(true); });
cmd->setParentWidget(q);
cmd->start();
});
}
if (subkey.isSecret()) {
hasActions = true;
auto action = menu->addAction(QIcon::fromTheme(QStringLiteral("send-to-symbolic")),
i18n("Transfer to smartcard"),
q, [this, subkey]() {
auto cmd = new KeyToCardCommand(subkey);
ui.subkeysTree->setEnabled(false);
connect(cmd, &KeyToCardCommand::finished,
q, [this]() { ui.subkeysTree->setEnabled(true); });
cmd->setParentWidget(q);
cmd->start();
});
action->setEnabled(!KeyToCardCommand::getSuitableCards(subkey).empty());
}
#ifdef QGPGME_SUPPORTS_SECRET_SUBKEY_EXPORT
const bool isPrimarySubkey = subkey.keyID() == key.keyID();
if (isOpenPGPKey && subkey.isSecret() && !isPrimarySubkey) {
hasActions = true;
menu->addAction(QIcon::fromTheme(QStringLiteral("view-certificate-export")),
i18n("Export secret subkey"),
q, [this, subkey]() {
auto cmd = new ExportSecretSubkeyCommand{{subkey}};
ui.subkeysTree->setEnabled(false);
connect(cmd, &ExportSecretSubkeyCommand::finished,
q, [this]() { ui.subkeysTree->setEnabled(true); });
cmd->setParentWidget(q);
cmd->start();
});
}
#endif
if (hasActions) {
menu->popup(ui.subkeysTree->viewport()->mapToGlobal(p));
} else {
delete menu;
}
}
SubKeysWidget::SubKeysWidget(QWidget *parent)
: QWidget(parent)
, d(new Private(this))
{
}
SubKeysWidget::~SubKeysWidget()
{
}
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 subkeys = key.subkeys(); const auto &subkey : subkeys) {
+ const auto subkeys = key.subkeys();
+ for (const auto &subkey : subkeys) {
auto item = new QTreeWidgetItem;
item->setData(0, Qt::DisplayRole, Formatting::prettyID(subkey.keyID()));
item->setData(0, Qt::AccessibleTextRole, Formatting::accessibleHexID(subkey.keyID()));
item->setData(0, Qt::UserRole, QVariant::fromValue(subkey));
item->setData(1, Qt::DisplayRole, Kleo::Formatting::type(subkey));
item->setData(2, Qt::DisplayRole, Kleo::Formatting::creationDateString(subkey));
item->setData(2, Qt::AccessibleTextRole, Formatting::accessibleCreationDate(subkey));
item->setData(3, Qt::DisplayRole, Kleo::Formatting::expirationDateString(subkey));
item->setData(3, Qt::AccessibleTextRole, Formatting::accessibleExpirationDate(subkey));
item->setData(4, Qt::DisplayRole, Kleo::Formatting::validityShort(subkey));
switch (subkey.publicKeyAlgorithm()) {
case GpgME::Subkey::AlgoECDSA:
case GpgME::Subkey::AlgoEDDSA:
case GpgME::Subkey::AlgoECDH:
item->setData(5, Qt::DisplayRole, QString::fromStdString(subkey.algoName()));
break;
default:
item->setData(5, Qt::DisplayRole, QString::number(subkey.length()));
}
item->setData(6, Qt::DisplayRole, Kleo::Formatting::usageString(subkey));
const auto isPrimary = subkey.keyID() == key.keyID();
item->setData(7, Qt::DisplayRole, isPrimary ? QStringLiteral("✓") : QString());
item->setData(7, Qt::AccessibleTextRole, isPrimary ? i18nc("yes, is primary key", "yes") : i18nc("no, is not primary key", "no"));
if (subkey.isCardKey()) {
if (const char *serialNo = subkey.cardSerialNumber()) {
item->setData(8, Qt::DisplayRole, i18nc("smart card <serial number>", "smart card %1", QString::fromUtf8(serialNo)));
} else {
item->setData(8, Qt::DisplayRole, i18n("smart card"));
}
} else if (isPrimary && key.hasSecret() && !subkey.isSecret()) {
item->setData(8, Qt::DisplayRole, i18nc("key is 'offline key', i.e. secret key is not stored on this computer", "offline"));
} else if (subkey.isSecret()) {
item->setData(8, Qt::DisplayRole, i18n("on this computer"));
} else {
item->setData(8, Qt::DisplayRole, i18nc("unknown storage location", "unknown"));
}
d->ui.subkeysTree->addTopLevelItem(item);
if (subkey.fingerprint() == selectedKeyFingerprint) {
d->ui.subkeysTree->setCurrentItem(item);
}
}
if (!key.hasSecret()) {
// hide information about storage location for keys of other people
d->ui.subkeysTree->hideColumn(8);
}
d->ui.subkeysTree->header()->resizeSections(QHeaderView::ResizeToContents);
}
GpgME::Key SubKeysWidget::key() const
{
return d->key;
}
SubKeysDialog::SubKeysDialog(QWidget *parent)
: QDialog(parent)
{
setWindowTitle(i18nc("@title:window", "Subkeys Details"));
auto l = new QVBoxLayout(this);
l->addWidget(new SubKeysWidget(this));
auto bbox = new QDialogButtonBox(this);
auto btn = bbox->addButton(QDialogButtonBox::Close);
connect(btn, &QPushButton::clicked, this, &QDialog::accept);
l->addWidget(bbox);
readConfig();
}
SubKeysDialog::~SubKeysDialog()
{
writeConfig();
}
void SubKeysDialog::readConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), "SubKeysDialog");
const QSize size = dialog.readEntry("Size", QSize(820, 280));
if (size.isValid()) {
resize(size);
}
}
void SubKeysDialog::writeConfig()
{
KConfigGroup dialog(KSharedConfig::openStateConfig(), "SubKeysDialog");
dialog.writeEntry("Size", size());
dialog.sync();
}
void SubKeysDialog::setKey(const GpgME::Key &key)
{
auto w = findChild<SubKeysWidget*>();
Q_ASSERT(w);
w->setKey(key);
}
GpgME::Key SubKeysDialog::key() const
{
auto w = findChild<SubKeysWidget*>();
Q_ASSERT(w);
return w->key();
}
diff --git a/src/utils/gui-helper.cpp b/src/utils/gui-helper.cpp
index 964dd7002..cd605c2bd 100644
--- a/src/utils/gui-helper.cpp
+++ b/src/utils/gui-helper.cpp
@@ -1,159 +1,161 @@
/* crypto/gui/signencryptemailconflictdialog.cpp
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2017 Intevation GmbH
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "gui-helper.h"
#include <QDialog>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QWidget>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
/* This is a Hack to workaround the fact that Foregrounding
a Window is so restricted that it AllowSetForegroundWindow
does not always work e.g. when the ForegroundWindow timeout
has not expired. This Hack is semi official but may stop
working in future windows versions.
This is similar to what pinentry-qt does on Windows.
*/
#ifdef Q_OS_WIN
WINBOOL SetForegroundWindowEx(HWND hWnd)
{
//Attach foreground window thread to our thread
const DWORD ForeGroundID = GetWindowThreadProcessId(::GetForegroundWindow(), NULL);
const DWORD CurrentID = GetCurrentThreadId();
WINBOOL retval;
AttachThreadInput(ForeGroundID, CurrentID, TRUE);
//Do our stuff here
HWND hLastActivePopupWnd = GetLastActivePopup(hWnd);
retval = SetForegroundWindow(hLastActivePopupWnd);
//Detach the attached thread
AttachThreadInput(ForeGroundID, CurrentID, FALSE);
return retval;
}// End SetForegroundWindowEx
#endif
void Kleo::aggressive_raise(QWidget *w, bool stayOnTop)
{
/* Maybe Qt will become aggressive enough one day that
* this is enough on windows too*/
w->raise();
w->setWindowState(Qt::WindowActive);
w->activateWindow();
#ifdef Q_OS_WIN
HWND wid = (HWND)w->effectiveWinId();
/* In the meantime we do our own attention grabbing */
if (!SetForegroundWindow(wid) && !SetForegroundWindowEx(wid)) {
OutputDebugStringA("SetForegroundWindow (ex) failed");
/* Yet another fallback which will not work on some
* versions and is not recommended by msdn */
if (!ShowWindow(wid, SW_SHOWNORMAL)) {
OutputDebugStringA("ShowWindow failed.");
}
}
/* Even if SetForgeoundWindow / SetForegroundWinowEx don't fail
* we sometimes are still not in the foreground. So we try yet
* another hack by using SetWindowPos */
if (!SetWindowPos(wid, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW)) {
OutputDebugStringA("SetWindowPos failed.");
}
/* sometimes we want to stay on top even if the user
* changes focus because we are _aggressive_ and otherwise
* Outlook might show the "Help I'm unresponsive so I must have
* crashed" Popup if the user clicks into Outlook while a dialog
* from us is active. */
else if (!stayOnTop) {
// Without moving back to NOTOPMOST we just stay on top.
// Even if the user changes focus.
SetWindowPos(wid, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
#else
Q_UNUSED(stayOnTop)
#endif
}
void Kleo::forceSetTabOrder(QWidget *first, QWidget *second)
{
if (!first || !second || first == second) {
return;
}
// temporarily change the focus policy of the two widgets to something
// other than Qt::NoFocus because QWidget::setTabOrder() does nothing
// if either widget has focus policy Qt::NoFocus
const auto firstFocusPolicy = first->focusPolicy();
const auto secondFocusPolicy = second->focusPolicy();
if (firstFocusPolicy == Qt::NoFocus) {
first->setFocusPolicy(Qt::StrongFocus);
}
if (secondFocusPolicy == Qt::NoFocus) {
second->setFocusPolicy(Qt::StrongFocus);
}
QWidget::setTabOrder(first, second);
if (first->focusPolicy() != firstFocusPolicy) {
first->setFocusPolicy(firstFocusPolicy);
}
if (second->focusPolicy() != secondFocusPolicy) {
second->setFocusPolicy(secondFocusPolicy);
}
}
template<typename UnaryPredicate>
bool focusFirstButtonIf(const std::vector<QAbstractButton *> &buttons, UnaryPredicate p)
{
auto it = std::find_if(std::begin(buttons), std::end(buttons), p);
if (it != std::end(buttons)) {
(*it)->setFocus();
return true;
}
return false;
}
bool Kleo::focusFirstCheckedButton(const std::vector<QAbstractButton *> &buttons)
{
return focusFirstButtonIf(buttons,
[](auto btn) {
return btn && btn->isEnabled() && btn->isChecked();
});
}
bool Kleo::focusFirstEnabledButton(const std::vector<QAbstractButton *> &buttons)
{
return focusFirstButtonIf(buttons,
[](auto btn) {
return btn && btn->isEnabled();
});
}
void Kleo::unsetDefaultButtons(const QDialogButtonBox *buttonBox)
{
if (!buttonBox) {
return;
}
- for (const auto buttons = buttonBox->buttons(); auto button : buttons) {
+ const auto buttons = buttonBox->buttons();
+ for (auto button : buttons) {
if (auto pushButton = qobject_cast<QPushButton *>(button)) {
pushButton->setDefault(false);
}
}
}
void Kleo::unsetAutoDefaultButtons(const QDialog *dialog)
{
if (!dialog) {
return;
}
- for (const auto pushButtons = dialog->findChildren<QPushButton *>(); auto pushButton : pushButtons) {
+ const auto pushButtons = dialog->findChildren<QPushButton *>();
+ for (auto pushButton : pushButtons) {
pushButton->setAutoDefault(false);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Dec 23, 1:36 PM (15 m, 58 s)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
92/5c/ca6e85e187d4917ee10a4e5dafb9
Attached To
rKLEOPATRA Kleopatra
Event Timeline
Log In to Comment