Page MenuHome GnuPG

No OneTemporary

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index fb7047cc8..eacd2a230 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,628 +1,630 @@
# SPDX-FileCopyrightText: none
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(mimetypes)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
if (NOT DISABLE_KWATCHGNUPG)
add_subdirectory(kwatchgnupg)
endif()
add_subdirectory(conf)
if(WIN32)
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_win.cpp)
set(_kleopatra_extra_SRCS
pics/gpg4win.qrc
selftest/registrycheck.cpp selftest/registrycheck.h
utils/gnupg-registry.c
utils/userinfo_win.cpp
utils/winapi-helpers.cpp utils/winapi-helpers.h
utils/windowsprocessdevice.cpp utils/windowsprocessdevice.h
versioninfo.rc kleopatra.w32-manifest
)
else()
set(_kleopatra_extra_uiserver_SRCS uiserver/uiserver_unix.cpp)
set(_kleopatra_extra_SRCS)
endif()
set(_kleopatra_uiserver_SRCS
${_kleopatra_extra_uiserver_SRCS}
selftest/uiservercheck.cpp selftest/uiservercheck.h
uiserver/assuanserverconnection.cpp uiserver/assuanserverconnection.h
uiserver/createchecksumscommand.cpp uiserver/createchecksumscommand.h
uiserver/decryptverifycommandemailbase.cpp uiserver/decryptverifycommandemailbase.h
uiserver/decryptverifycommandfilesbase.cpp uiserver/decryptverifycommandfilesbase.h
uiserver/echocommand.cpp uiserver/echocommand.h
uiserver/encryptcommand.cpp uiserver/encryptcommand.h
uiserver/importfilescommand.cpp uiserver/importfilescommand.h
uiserver/prepencryptcommand.cpp uiserver/prepencryptcommand.h
uiserver/prepsigncommand.cpp uiserver/prepsigncommand.h
uiserver/selectcertificatecommand.cpp
uiserver/sessiondata.cpp uiserver/sessiondata.h
uiserver/signcommand.cpp uiserver/signcommand.h
uiserver/signencryptfilescommand.cpp
uiserver/uiserver.cpp
uiserver/verifychecksumscommand.cpp uiserver/verifychecksumscommand.h
)
set(_kleopatra_uiserver_extra_libs LibAssuan::LibAssuan LibGpgError::LibGpgError)
if(HAVE_GPG_ERR_SOURCE_KLEO)
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO)
add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_KLEO)
else()
add_definitions(-DGPG_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1)
add_definitions(-DGPGMEPP_ERR_SOURCE_DEFAULT=GPG_ERR_SOURCE_USER_1)
endif()
if(KPim6IdentityManagementCore_FOUND AND KPim6MailTransport_FOUND AND KPim6AkonadiMime_FOUND)
set(_kleopatra_mail_libs
KPim6::IdentityManagementCore # Export OpenPGP keys using WKS
KPim6::MailTransport
KPim6::AkonadiMime
)
add_definitions(-DMAILAKONADI_ENABLED)
endif()
ki18n_wrap_ui(_kleopatra_uiserver_SRCS crypto/gui/signingcertificateselectionwidget.ui)
configure_file(kleopatra.qrc.in kleopatra.qrc @ONLY)
set(_kleopatra_SRCS
${_kleopatra_extra_SRCS}
accessibility/accessiblelink.cpp
accessibility/accessiblelink_p.h
accessibility/accessiblerichtextlabel.cpp
accessibility/accessiblerichtextlabel_p.h
accessibility/accessiblevaluelabel.cpp
accessibility/accessiblevaluelabel_p.h
accessibility/accessiblewidgetfactory.cpp
accessibility/accessiblewidgetfactory.h
commands/addadskcommand.cpp
commands/addadskcommand.h
commands/addsubkeycommand.cpp
commands/addsubkeycommand.h
commands/adduseridcommand.cpp
commands/adduseridcommand.h
commands/authenticatepivcardapplicationcommand.cpp
commands/authenticatepivcardapplicationcommand.h
commands/cardcommand.cpp
commands/cardcommand.h
commands/certificatetocardcommand.cpp
commands/certificatetocardcommand.h
commands/certificatetopivcardcommand.cpp
commands/certificatetopivcardcommand.h
commands/certifycertificatecommand.cpp
commands/certifycertificatecommand.h
commands/certifygroupcommand.cpp
commands/certifygroupcommand.h
commands/changeexpirycommand.cpp
commands/changeexpirycommand.h
commands/changeownertrustcommand.cpp
commands/changeownertrustcommand.h
commands/changepassphrasecommand.cpp
commands/changepassphrasecommand.h
commands/changepincommand.cpp
commands/changepincommand.h
commands/changeroottrustcommand.cpp
commands/changeroottrustcommand.h
commands/checksumcreatefilescommand.cpp
commands/checksumcreatefilescommand.h
commands/checksumverifyfilescommand.cpp
commands/checksumverifyfilescommand.h
commands/clearcrlcachecommand.cpp
commands/clearcrlcachecommand.h
commands/command.cpp
commands/command.h
commands/createcsrforcardkeycommand.cpp
commands/createcsrforcardkeycommand.h
commands/creategroupcommand.cpp
commands/creategroupcommand.h
commands/createopenpgpkeyfromcardkeyscommand.cpp
commands/createopenpgpkeyfromcardkeyscommand.h
commands/decryptverifyclipboardcommand.cpp
commands/decryptverifyclipboardcommand.h
commands/decryptverifyfilescommand.cpp
commands/decryptverifyfilescommand.h
commands/deletecertificatescommand.cpp
commands/deletecertificatescommand.h
commands/detailscommand.cpp
commands/detailscommand.h
commands/dumpcertificatecommand.cpp
commands/dumpcertificatecommand.h
commands/dumpcrlcachecommand.cpp
commands/dumpcrlcachecommand.h
commands/exportcertificatecommand.cpp
commands/exportcertificatecommand.h
commands/exportgroupscommand.cpp
commands/exportgroupscommand.h
commands/exportopenpgpcertstoservercommand.cpp
commands/exportopenpgpcertstoservercommand.h
commands/exportopenpgpcerttoprovidercommand.cpp
commands/exportopenpgpcerttoprovidercommand.h
commands/exportpaperkeycommand.cpp
commands/exportpaperkeycommand.h
commands/exportsecretkeycommand.cpp
commands/exportsecretkeycommand.h
commands/exportsecretsubkeycommand.cpp
commands/exportsecretsubkeycommand.h
+ commands/exportsecretteamkeycommand.cpp
+ commands/exportsecretteamkeycommand.h
commands/generateopenpgpcardkeysandcertificatecommand.cpp
commands/generateopenpgpcardkeysandcertificatecommand.h
commands/genrevokecommand.cpp
commands/genrevokecommand.h
commands/gnupgprocesscommand.cpp
commands/gnupgprocesscommand.h
commands/importcertificatefromclipboardcommand.cpp
commands/importcertificatefromclipboardcommand.h
commands/importcertificatefromdatacommand.cpp
commands/importcertificatefromdatacommand.h
commands/importcertificatefromfilecommand.cpp
commands/importcertificatefromfilecommand.h
commands/importcertificatefromkeyservercommand.cpp
commands/importcertificatefromkeyservercommand.h
commands/importcertificatefrompivcardcommand.cpp
commands/importcertificatefrompivcardcommand.h
commands/importcertificatescommand.cpp
commands/importcertificatescommand.h
commands/importcrlcommand.cpp
commands/importcrlcommand.h
commands/importpaperkeycommand.cpp
commands/importpaperkeycommand.h
commands/keytocardcommand.cpp
commands/keytocardcommand.h
commands/lookupcertificatescommand.cpp
commands/lookupcertificatescommand.h
commands/newcertificatesigningrequestcommand.cpp
commands/newcertificatesigningrequestcommand.h
commands/newopenpgpcertificatecommand.cpp
commands/newopenpgpcertificatecommand.h
commands/openpgpgeneratecardkeycommand.cpp
commands/openpgpgeneratecardkeycommand.h
commands/pivgeneratecardkeycommand.cpp
commands/pivgeneratecardkeycommand.h
commands/refreshcertificatescommand.cpp
commands/refreshcertificatescommand.h
commands/reloadkeyscommand.cpp
commands/reloadkeyscommand.h
commands/revokecertificationcommand.cpp
commands/revokecertificationcommand.h
commands/revokekeycommand.cpp
commands/revokekeycommand.h
commands/revokeuseridcommand.cpp
commands/revokeuseridcommand.h
commands/selftestcommand.cpp
commands/selftestcommand.h
commands/setinitialpincommand.cpp
commands/setinitialpincommand.h
commands/setpivcardapplicationadministrationkeycommand.cpp
commands/setpivcardapplicationadministrationkeycommand.h
commands/setprimaryuseridcommand.cpp
commands/setprimaryuseridcommand.h
commands/signencryptclipboardcommand.cpp
commands/signencryptclipboardcommand.h
commands/signencryptfilescommand.cpp
commands/signencryptfilescommand.h
commands/signencryptfoldercommand.cpp
commands/signencryptfoldercommand.h
commands/togglecertificateenabledcommand.cpp
commands/togglecertificateenabledcommand.h
commands/viewemailfilescommand.cpp
commands/viewemailfilescommand.h
conf/configuredialog.cpp
conf/configuredialog.h
conf/groupsconfigdialog.cpp
conf/groupsconfigdialog.h
conf/groupsconfigwidget.cpp
conf/groupsconfigwidget.h
crypto/decryptverifyfilescontroller.cpp
crypto/decryptverifyfilescontroller.h
crypto/certificateresolver.cpp
crypto/certificateresolver.h
crypto/checksumsutils_p.cpp
crypto/checksumsutils_p.h
crypto/controller.cpp
crypto/controller.h
crypto/createchecksumscontroller.cpp
crypto/createchecksumscontroller.h
crypto/decryptverifyemailcontroller.cpp
crypto/decryptverifyemailcontroller.h
crypto/decryptverifytask.cpp
crypto/decryptverifytask.h
crypto/encryptemailcontroller.cpp
crypto/encryptemailcontroller.h
crypto/encryptemailtask.cpp
crypto/encryptemailtask.h
crypto/gui/certificatelineedit.cpp
crypto/gui/certificatelineedit.h
crypto/gui/certificateselectionline.cpp
crypto/gui/certificateselectionline.h
crypto/gui/decryptverifyfilesdialog.cpp
crypto/gui/decryptverifyfilesdialog.h
crypto/gui/encryptemailwizard.cpp
crypto/gui/encryptemailwizard.h
crypto/gui/newresultpage.cpp
crypto/gui/newresultpage.h
crypto/gui/objectspage.cpp
crypto/gui/objectspage.h
crypto/gui/resolverecipientspage.cpp
crypto/gui/resolverecipientspage.h
crypto/gui/resultitemwidget.cpp
crypto/gui/resultitemwidget.h
crypto/gui/resultlistwidget.cpp
crypto/gui/resultlistwidget.h
crypto/gui/resultpage.cpp
crypto/gui/resultpage.h
crypto/gui/signemailwizard.cpp
crypto/gui/signemailwizard.h
crypto/gui/signencryptemailconflictdialog.cpp
crypto/gui/signencryptemailconflictdialog.h
crypto/gui/signencryptfilesdialog.cpp
crypto/gui/signencryptfilesdialog.h
crypto/gui/signencryptwidget.cpp
crypto/gui/signencryptwidget.h
crypto/gui/signencryptwizard.cpp
crypto/gui/signencryptwizard.h
crypto/gui/signerresolvepage.cpp
crypto/gui/signerresolvepage.h
crypto/gui/signingcertificateselectiondialog.cpp
crypto/gui/signingcertificateselectiondialog.h
crypto/gui/signingcertificateselectionwidget.cpp
crypto/gui/signingcertificateselectionwidget.h
crypto/gui/unknownrecipientwidget.cpp
crypto/gui/unknownrecipientwidget.h
crypto/gui/verifychecksumsdialog.cpp
crypto/gui/verifychecksumsdialog.h
crypto/gui/wizard.cpp
crypto/gui/wizard.h
crypto/gui/wizardpage.cpp
crypto/gui/wizardpage.h
crypto/newsignencryptemailcontroller.cpp
crypto/newsignencryptemailcontroller.h
crypto/recipient.cpp
crypto/recipient.h
crypto/sender.cpp
crypto/sender.h
crypto/signemailcontroller.cpp
crypto/signemailcontroller.h
crypto/signemailtask.cpp
crypto/signemailtask.h
crypto/signencryptfilescontroller.cpp
crypto/signencryptfilescontroller.h
crypto/signencrypttask.cpp
crypto/signencrypttask.h
crypto/task.cpp
crypto/task.h
crypto/taskcollection.cpp
crypto/taskcollection.h
crypto/verifychecksumscontroller.cpp
crypto/verifychecksumscontroller.h
dialogs/addsubkeydialog.cpp
dialogs/addsubkeydialog.h
dialogs/adduseriddialog.cpp
dialogs/adduseriddialog.h
dialogs/certificatedetailsdialog.cpp
dialogs/certificatedetailsdialog.h
dialogs/certificatedetailswidget.cpp
dialogs/certificatedetailswidget.h
dialogs/certificatedumpwidget.cpp
dialogs/certificatedumpwidget.h
dialogs/certificateselectiondialog.cpp
dialogs/certificateselectiondialog.h
dialogs/certifycertificatedialog.cpp
dialogs/certifycertificatedialog.h
dialogs/certifywidget.cpp
dialogs/certifywidget.h
dialogs/createcsrdialog.cpp
dialogs/createcsrdialog.h
dialogs/copytosmartcarddialog.cpp
dialogs/copytosmartcarddialog.h
dialogs/debugdialog.cpp
dialogs/debugdialog.h
dialogs/deletecertificatesdialog.cpp
dialogs/deletecertificatesdialog.h
dialogs/editgroupdialog.cpp
dialogs/editgroupdialog.h
dialogs/expirydialog.cpp
dialogs/expirydialog.h
dialogs/exportdialog.cpp
dialogs/exportdialog.h
dialogs/gencardkeydialog.cpp
dialogs/gencardkeydialog.h
dialogs/groupdetailsdialog.cpp
dialogs/groupdetailsdialog.h
dialogs/importedcertificatesdialog.cpp
dialogs/importedcertificatesdialog.h
dialogs/lookupcertificatesdialog.cpp
dialogs/lookupcertificatesdialog.h
dialogs/padwindow.cpp
dialogs/padwindow.h
dialogs/pivcardapplicationadministrationkeyinputdialog.cpp
dialogs/pivcardapplicationadministrationkeyinputdialog.h
dialogs/revokekeydialog.cpp
dialogs/revokekeydialog.h
dialogs/revokerswidget.cpp
dialogs/revokerswidget.h
dialogs/selftestdialog.cpp
dialogs/selftestdialog.h
dialogs/setinitialpindialog.cpp
dialogs/setinitialpindialog.h
dialogs/signencryptclipboarddialog.cpp
dialogs/signencryptclipboarddialog.h
dialogs/smartcardwindow.cpp
dialogs/smartcardwindow.h
dialogs/subkeyswidget.cpp
dialogs/subkeyswidget.h
dialogs/trustchainwidget.cpp
dialogs/trustchainwidget.h
dialogs/updatenotification.cpp
dialogs/updatenotification.h
dialogs/useridswidget.cpp
dialogs/useridswidget.h
dialogs/weboftrustwidget.cpp
dialogs/weboftrustwidget.h
interfaces/anchorprovider.h
interfaces/focusfirstchild.h
selftest/compliancecheck.cpp
selftest/compliancecheck.h
selftest/enginecheck.cpp
selftest/enginecheck.h
selftest/gpgagentcheck.cpp
selftest/gpgagentcheck.h
selftest/gpgconfcheck.cpp
selftest/gpgconfcheck.h
selftest/libkleopatrarccheck.cpp
selftest/libkleopatrarccheck.h
selftest/selftest.cpp
selftest/selftest.h
selftest/testuiserver.cpp
selftest/testuiserver.h
smartcard/algorithminfo.h
smartcard/card.cpp
smartcard/card.h
smartcard/deviceinfowatcher.cpp
smartcard/deviceinfowatcher.h
smartcard/keypairinfo.cpp
smartcard/keypairinfo.h
smartcard/netkeycard.cpp
smartcard/netkeycard.h
smartcard/openpgpcard.cpp
smartcard/openpgpcard.h
smartcard/p15card.cpp
smartcard/p15card.h
smartcard/pivcard.cpp
smartcard/pivcard.h
smartcard/readerstatus.cpp
smartcard/readerstatus.h
smartcard/utils.cpp
smartcard/utils.h
utils/accessibility.cpp
utils/accessibility.h
utils/action_data.cpp
utils/action_data.h
utils/applicationstate.cpp
utils/applicationstate.h
utils/archivedefinition.cpp
utils/archivedefinition.h
utils/certificatepair.h
utils/clipboardmenu.cpp
utils/clipboardmenu.h
utils/csrutils.cpp
utils/csrutils.h
utils/debug-helpers.cpp
utils/debug-helpers.h
utils/dragqueen.cpp
utils/dragqueen.h
utils/email.cpp
utils/email.h
utils/emptypassphraseprovider.cpp
utils/emptypassphraseprovider.h
utils/filedialog.cpp
utils/filedialog.h
utils/fileutils.cpp
utils/fileutils.h
utils/gui-helper.cpp
utils/gui-helper.h
utils/headerview.cpp
utils/headerview.h
utils/input.cpp
utils/input.h
utils/iodevicelogger.cpp
utils/iodevicelogger.h
utils/kdpipeiodevice.cpp
utils/kdpipeiodevice.h
utils/keyexportdraghandler.cpp
utils/keyexportdraghandler.h
utils/kuniqueservice.cpp
utils/kuniqueservice.h
utils/log.cpp
utils/log.h
utils/memory-helpers.h
utils/migration.cpp
utils/migration.h
utils/output.cpp
utils/output.h
utils/overwritedialog.cpp
utils/overwritedialog.h
utils/path-helper.cpp
utils/path-helper.h
utils/statusmessage.cpp
utils/statusmessage.h
utils/systemtrayicon.cpp
utils/systemtrayicon.h
utils/tags.cpp
utils/tags.h
utils/types.cpp
utils/types.h
utils/userinfo.cpp
utils/userinfo.h
utils/writecertassuantransaction.cpp
utils/writecertassuantransaction.h
utils/wsastarter.cpp
utils/wsastarter.h
view/anchorcache.cpp
view/anchorcache_p.h
view/cardkeysview.cpp
view/cardkeysview.h
view/htmllabel.cpp
view/htmllabel.h
view/infofield.cpp
view/infofield.h
view/keycacheoverlay.cpp
view/keycacheoverlay.h
view/keylistcontroller.cpp
view/keylistcontroller.h
view/keytreeview.cpp
view/keytreeview.h
view/netkeywidget.cpp
view/netkeywidget.h
view/overlaywidget.cpp
view/overlaywidget.h
view/p15cardwidget.cpp
view/p15cardwidget.h
view/padwidget.cpp
view/padwidget.h
view/pgpcardwidget.cpp
view/pgpcardwidget.h
view/pivcardwidget.cpp
view/pivcardwidget.h
view/progressoverlay.cpp
view/progressoverlay.h
view/searchbar.cpp
view/searchbar.h
view/smartcardactions.cpp
view/smartcardactions.h
view/smartcardswidget.cpp
view/smartcardswidget.h
view/smartcardwidget.cpp
view/smartcardwidget.h
view/tabwidget.cpp
view/tabwidget.h
view/textoverlay.cpp
view/textoverlay.h
view/waitwidget.cpp
view/waitwidget.h
view/welcomewidget.cpp
view/welcomewidget.h
aboutdata.cpp
aboutdata.h
${CMAKE_CURRENT_BINARY_DIR}/kleopatra.qrc
kleopatraapplication.cpp
kleopatraapplication.h
main.cpp
mainwindow.cpp
mainwindow.h
systrayicon.cpp
systrayicon.h
kleopatra_options.h
)
if(WIN32)
configure_file (versioninfo.rc.in versioninfo.rc)
configure_file (kleopatra.w32-manifest.in kleopatra.w32-manifest)
set(_kleopatra_SRCS
${CMAKE_CURRENT_BINARY_DIR}/kleopatra.w32-manifest
${CMAKE_CURRENT_BINARY_DIR}/versioninfo.rc
conf/kmessageboxdontaskagainstorage.cpp
conf/kmessageboxdontaskagainstorage.h
${_kleopatra_SRCS}
)
endif()
set (_kleopatra_SRCS conf/kleopageconfigdialog.cpp conf/kleopageconfigdialog.h ${_kleopatra_SRCS})
ecm_qt_declare_logging_category(_kleopatra_SRCS HEADER kleopatra_debug.h IDENTIFIER KLEOPATRA_LOG CATEGORY_NAME org.kde.pim.kleopatra
DESCRIPTION "kleopatra (kleopatra)"
OLD_CATEGORY_NAMES log_kleopatra
EXPORT KLEOPATRA
)
if(KLEO_MODEL_TEST)
add_definitions(-DKLEO_MODEL_TEST)
set(_kleopatra_SRCS ${_kleopatra_SRCS} models/modeltest.cpp)
endif()
ki18n_wrap_ui(_kleopatra_SRCS
dialogs/setinitialpindialog.ui
)
kconfig_add_kcfg_files(_kleopatra_SRCS
kcfg/settings.kcfgc
)
# setting a different KLEOPATRA_ICON_DIR allows to use different icons for a customized build
if (NOT KLEOPATRA_ICON_DIR)
set(KLEOPATRA_ICON_DIR "${CMAKE_CURRENT_SOURCE_DIR}/icons")
endif()
file(GLOB ICONS_PNGS "${KLEOPATRA_ICON_DIR}/*.png")
file(GLOB ICONS_SVGS "${KLEOPATRA_ICON_DIR}/*.svg")
ecm_add_app_icon(_kleopatra_SRCS ICONS ${ICONS_PNGS} ${ICONS_SVGS})
if (NOT WIN32)
ecm_install_icons(ICONS ${ICONS_PNGS} ${ICONS_SVGS} DESTINATION ${KDE_INSTALL_ICONDIR})
else()
if (ICONS_SVGS)
list(GET ICONS_SVGS 0 app_icon_svg)
configure_file(icons/icons.qrc.in icons.qrc @ONLY)
set(_kleopatra_SRCS ${_kleopatra_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/icons.qrc)
endif()
endif()
add_executable(kleopatra_bin ${_kleopatra_SRCS} ${_kleopatra_uiserver_SRCS})
# For the ConfigureDialog & KCMs
target_link_libraries(kleopatra_bin kcm_kleopatra_static)
#if (COMPILE_WITH_UNITY_CMAKE_SUPPORT)
# set_target_properties(kleopatra_bin PROPERTIES UNITY_BUILD ON)
#endif()
set_target_properties(kleopatra_bin PROPERTIES OUTPUT_NAME kleopatra)
if (WIN32)
set(_kleopatra_platform_libs "secur32")
endif ()
target_link_libraries(kleopatra_bin
Gpgmepp
KPim6::Libkleo
KPim6::Mime
KPim6::MimeTreeParserWidgets
KF6::Codecs
KF6::CoreAddons
KF6::Crash
KF6::I18n
KF6::IconThemes
KF6::ItemModels
KF6::KIOCore
KF6::KIOWidgets
KF6::WindowSystem
KF6::XmlGui
Qt::Network
Qt::PrintSupport # Printing secret keys
${_kleopatra_extra_libs}
${_kleopatra_mail_libs}
${_kleopatra_uiserver_extra_libs}
${_kleopatra_dbusaddons_libs}
${_kleopatra_platform_libs}
)
target_link_libraries(kleopatra_bin QGpgmeQt6)
install(TARGETS kleopatra_bin ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
install(
PROGRAMS data/org.kde.kleopatra.desktop data/kleopatra_import.desktop
DESTINATION ${KDE_INSTALL_APPDIR}
)
install(FILES data/org.kde.kleopatra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES data/kleopatra-mime.xml DESTINATION ${KDE_INSTALL_MIMEDIR})
install(
PROGRAMS data/kleopatra_signencryptfiles.desktop
data/kleopatra_signencryptfolders.desktop
data/kleopatra_decryptverifyfiles.desktop
DESTINATION ${KDE_INSTALL_DATADIR}/kio/servicemenus
)
install(FILES kleopatradebugcommandsrc DESTINATION ${KDE_INSTALL_CONFDIR})
diff --git a/src/commands/command.h b/src/commands/command.h
index 6ee0785f7..eb975779c 100644
--- a/src/commands/command.h
+++ b/src/commands/command.h
@@ -1,137 +1,139 @@
/*
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <qwindowdefs.h> // for WId
#include <utils/types.h> // for ExecutionContext
#include <memory>
#include <vector>
template<typename T>
class QList;
class QAbstractItemView;
namespace GpgME
{
class Key;
}
namespace Kleo
{
class KeyListController;
class Command : public QObject, public ExecutionContext
{
Q_OBJECT
public:
explicit Command(KeyListController *parent);
explicit Command(QAbstractItemView *view, KeyListController *parent);
explicit Command(const GpgME::Key &key);
explicit Command(const std::vector<GpgME::Key> &keys);
~Command() override;
enum Restriction {
// clang-format off
NoRestriction = 0x0000,
NeedSelection = 0x0001,
OnlyOneKey = 0x0002,
NeedSecretKey = 0x0004, //< command performs secret key operations
NeedSecretPrimaryKeyData = 0x0008, //< command needs access to the secret key data of the primary key
NeedSecretSubkeyData = 0x0010, //< command needs access to the secret key data of one or more subkeys
// esoteric:
MayOnlyBeSecretKeyIfOwnerTrustIsNotYetUltimate = 0x0040, // for set-owner-trust
AnyCardHasNullPin = 0x0080,
SuitableForCard = 0x0100,
MustBeRoot = 0x0200,
MustBeTrustedRoot = 0x0400 | MustBeRoot,
MustBeUntrustedRoot = 0x0800 | MustBeRoot,
MustBeValid = 0x1000, //< key is neither revoked nor expired nor otherwise "bad"
MustBeOpenPGP = 0x2000,
MustBeCMS = 0x4000,
+ NeedSecretEncryptSubkey = 0x8000,
+
_AllRestrictions_Helper,
AllRestrictions = 2 * (_AllRestrictions_Helper - 1) - 1,
// clang-format on
};
Q_DECLARE_FLAGS(Restrictions, Restriction)
static Restrictions restrictions()
{
return NoRestriction;
}
/** Classify the files and return the most appropriate commands.
*
* @param files: A list of files.
*
* @returns null QString on success. Error message otherwise.
*/
static QList<Command *> commandsForFiles(const QStringList &files, KeyListController *controller);
/** Get a command for a query.
*
* @param query: A keyid / fingerprint or any string to use in the search.
*/
static Command *commandForQuery(const QString &query);
void setParentWidget(QWidget *widget);
// Prefer Command::setParentWidget over Command::setParentWId; QWidget::winId can cause unexpected problems
// when called on non-toplevel widgets
void setParentWId(WId wid);
void setView(QAbstractItemView *view);
void setKey(const GpgME::Key &key);
void setKeys(const std::vector<GpgME::Key> &keys);
void setAutoDelete(bool on);
bool autoDelete() const;
void setWarnWhenRunningAtShutdown(bool warn);
bool warnWhenRunningAtShutdown() const;
public Q_SLOTS:
void start();
void cancel();
Q_SIGNALS:
void info(const QString &message, int timeout = 0);
void progress(int current, int total);
void finished(QPrivateSignal);
void canceled(QPrivateSignal);
private:
virtual void doStart() = 0;
virtual void doCancel() = 0;
private:
void applyWindowID(QWidget *wid) const override;
protected:
class Private;
const std::unique_ptr<Private> d;
protected:
explicit Command(Private *pp);
explicit Command(QAbstractItemView *view, Private *pp);
explicit Command(const std::vector<GpgME::Key> &keys, Private *pp);
explicit Command(const GpgME::Key &key, Private *pp);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Command::Restrictions)
}
diff --git a/src/commands/exportsecretteamkeycommand.cpp b/src/commands/exportsecretteamkeycommand.cpp
new file mode 100644
index 000000000..cbc99925c
--- /dev/null
+++ b/src/commands/exportsecretteamkeycommand.cpp
@@ -0,0 +1,350 @@
+// SPDX-FileCopyrightText: 2025 g10 Code GmbH
+// SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
+// SPDX-License-Identifier: LGPL-2.0-or-later
+
+#include <config-kleopatra.h>
+
+#include "exportsecretteamkeycommand.h"
+
+#include "command_p.h"
+
+#include <utils/applicationstate.h>
+#include <utils/filedialog.h>
+
+#include <settings.h>
+
+#include <Libkleo/AuditLogEntry>
+#include <Libkleo/Classify>
+#include <Libkleo/Formatting>
+
+#include <KLocalizedString>
+#include <KSharedConfig>
+
+#include <QGpgME/ExportJob>
+#include <QGpgME/Protocol>
+
+#include <QCheckBox>
+#include <QDialog>
+#include <QFileInfo>
+#include <QLabel>
+#include <QPushButton>
+#include <QStandardPaths>
+#include <QVBoxLayout>
+
+#include <gpgme++/context.h>
+
+#include <memory>
+
+#include <kleopatra_debug.h>
+
+using namespace Kleo;
+using namespace Kleo::Commands;
+using namespace GpgME;
+using namespace Qt::Literals::StringLiterals;
+
+namespace
+{
+
+QString openPGPCertificateFileExtension()
+{
+ return outputFileExtension(Class::OpenPGP | Class::Ascii | Class::Certificate, Settings().usePGPFileExt());
+}
+
+QString proposeFilename(const Key &key)
+{
+ QString filename;
+
+ auto name = Formatting::prettyName(key);
+ if (name.isEmpty()) {
+ name = Formatting::prettyEMail(key);
+ }
+ const auto keyID = Formatting::prettyKeyID(key.keyID());
+ /* Not translated so it's better to use in tutorials etc. */
+ filename = QStringView{u"%1_%2_SECRET_TEAM_KEY"}.arg(name, keyID);
+ filename.replace(u'/', u'_');
+
+ return ApplicationState::lastUsedExportDirectory() + u'/' + filename + u'.' + openPGPCertificateFileExtension();
+}
+
+QString requestFilename(const QString &proposedFilename, QWidget *parent)
+{
+ auto filename = FileDialog::getSaveFileNameEx(parent,
+ i18nc("@title:window", "Save Secret Team Key"),
+ QStringLiteral("imp"),
+ proposedFilename,
+ i18nc("description of filename filter", "Secret Key Files") + QLatin1StringView{" (*.asc *.gpg *.pgp)"});
+
+ if (!filename.isEmpty()) {
+ const QFileInfo fi{filename};
+ if (fi.suffix().isEmpty()) {
+ filename += u'.' + openPGPCertificateFileExtension();
+ }
+ ApplicationState::setLastUsedExportDirectory(filename);
+ }
+
+ return filename;
+}
+}
+
+class ExportSecretTeamKeyCommand::Private : public Command::Private
+{
+ friend class ::ExportSecretTeamKeyCommand;
+ ExportSecretTeamKeyCommand *q_func() const
+ {
+ return static_cast<ExportSecretTeamKeyCommand *>(q);
+ }
+
+public:
+ explicit Private(ExportSecretTeamKeyCommand *qq, KeyListController *c = nullptr);
+ ~Private() override;
+
+ void start();
+ void cancel();
+
+private:
+ std::unique_ptr<QGpgME::ExportJob> startExportJob(const Key &key, bool sign);
+ void onExportJobResult(const Error &err, const QByteArray &keyData, const AuditLogEntry &auditLog);
+ void showError(const Error &err, const AuditLogEntry &auditLog = {});
+ void prepareExport(bool sign);
+
+private:
+ QString filename;
+ QPointer<QGpgME::ExportJob> job;
+};
+
+ExportSecretTeamKeyCommand::Private *ExportSecretTeamKeyCommand::d_func()
+{
+ return static_cast<Private *>(d.get());
+}
+const ExportSecretTeamKeyCommand::Private *ExportSecretTeamKeyCommand::d_func() const
+{
+ return static_cast<const Private *>(d.get());
+}
+
+#define d d_func()
+#define q q_func()
+
+ExportSecretTeamKeyCommand::Private::Private(ExportSecretTeamKeyCommand *qq, KeyListController *c)
+ : Command::Private{qq, c}
+{
+}
+
+ExportSecretTeamKeyCommand::Private::~Private() = default;
+
+void ExportSecretTeamKeyCommand::Private::start()
+{
+ if (key().isNull()) {
+ finished();
+ return;
+ }
+
+ auto dialog = new QDialog(parentWidgetOrView());
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->setWindowTitle(i18nc("@title:dialog", "Save Secret Team Key"));
+
+ auto layout = new QVBoxLayout(dialog);
+
+ auto label = new QLabel(i18nc("@info", "After importing the team key, team members will be able to decrypt data with it."));
+ layout->addWidget(label);
+ auto signLabel = new QLabel(i18nc("@info",
+ "Please choose whether members should also be allowed to sign data with the team key.\n"
+ "Alternatively, they can use their personal key for signing."));
+
+ const auto subkeys = key().subkeys();
+ auto hasSecretSigningSubkey = std::ranges::any_of(std::span{subkeys}.subspan(1), [](const auto &subkey) {
+ return subkey.canSign() && !subkey.isBad() && subkey.isSecret();
+ });
+ signLabel->setVisible(hasSecretSigningSubkey);
+ layout->addWidget(signLabel);
+
+ auto signCheckbox = new QCheckBox(i18nc("@option:check", "Allow team members to sign with the team key"));
+ signCheckbox->setVisible(hasSecretSigningSubkey);
+
+ signCheckbox->setEnabled(hasSecretSigningSubkey);
+ layout->addWidget(signCheckbox);
+
+ auto noteLabel = new QLabel(i18nc("@info", "Team members will not be able to change the name, email address, or expiration date of the team key."));
+ layout->addWidget(noteLabel);
+
+ layout->addStretch();
+
+ auto buttonBox = new QDialogButtonBox;
+
+ auto saveButton = buttonBox->addButton(QDialogButtonBox::Save);
+ connect(saveButton, &QPushButton::clicked, q, [dialog, this, signCheckbox]() {
+ dialog->accept();
+ prepareExport(signCheckbox->isChecked());
+ });
+
+ auto cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel);
+ connect(cancelButton, &QPushButton::clicked, q, [dialog, this]() {
+ dialog->reject();
+ q->cancel();
+ });
+
+ layout->addWidget(buttonBox);
+
+ dialog->open();
+}
+
+void ExportSecretTeamKeyCommand::Private::cancel()
+{
+ if (job) {
+ job->slotCancel();
+ }
+ job.clear();
+}
+
+std::unique_ptr<QGpgME::ExportJob> ExportSecretTeamKeyCommand::Private::startExportJob(const Key &key, bool sign)
+{
+ const auto armor = filename.endsWith(".asc"_L1, Qt::CaseInsensitive);
+
+ QStringList fingerprints;
+
+ auto subkeys = key.subkeys();
+ std::sort(subkeys.begin(), subkeys.end(), [](const auto left, const auto right) {
+ return left.creationTime() > right.creationTime();
+ });
+ auto haveEncrypt = false;
+ auto haveSign = false;
+
+ for (const auto &subkey : subkeys) {
+ if (subkey.canCertify()) {
+ continue;
+ }
+ if (subkey.canSign() && !sign) {
+ continue;
+ }
+ if (!subkey.isSecret()) {
+ continue;
+ }
+ if (subkey.isBad()) {
+ continue;
+ }
+ if (subkey.canSign()) {
+ if (haveSign) {
+ continue;
+ } else {
+ haveSign = true;
+ }
+ }
+
+ if (subkey.canEncrypt()) {
+ if (haveEncrypt) {
+ continue;
+ } else {
+ haveEncrypt = true;
+ }
+ }
+ fingerprints.append(QString::fromLatin1(subkey.fingerprint()) + u"!"_s);
+ }
+
+ std::unique_ptr<QGpgME::ExportJob> exportJob{QGpgME::openpgp()->secretSubkeyExportJob(armor)};
+ Q_ASSERT(exportJob);
+
+ connect(exportJob.get(), &QGpgME::ExportJob::result, q, [this](const auto &err, const auto &keyData, const auto auditLogAsHtml, const auto &auditLogError) {
+ onExportJobResult(err, keyData, AuditLogEntry{auditLogAsHtml, auditLogError});
+ });
+ connect(exportJob.get(), &QGpgME::Job::jobProgress, q, &Command::progress);
+
+ const auto err = exportJob->start(fingerprints);
+ if (err) {
+ showError(err);
+ return {};
+ }
+ Q_EMIT q->info(i18nc("@info:status", "Saving secret team key..."));
+
+ return exportJob;
+}
+
+void ExportSecretTeamKeyCommand::Private::onExportJobResult(const Error &err, const QByteArray &keyData, const AuditLogEntry &auditLog)
+{
+ if (err.isCanceled()) {
+ finished();
+ return;
+ }
+
+ if (err) {
+ showError(err, auditLog);
+ finished();
+ return;
+ }
+
+ if (keyData.isEmpty()) {
+ error(i18nc("@info", "The result is empty. Maybe you entered an empty or a wrong passphrase."));
+ finished();
+ return;
+ }
+
+ QFile f{filename};
+ if (!f.open(QIODevice::WriteOnly)) {
+ error(xi18nc("@info", "Cannot open file <filename>%1</filename> for writing.", filename));
+ finished();
+ return;
+ }
+
+ const auto bytesWritten = f.write(keyData);
+ if (bytesWritten != keyData.size()) {
+ error(xi18nc("@info", "Writing key to file <filename>%1</filename> failed.", filename));
+ finished();
+ return;
+ }
+
+ information(xi18nc("@info", "The secret team key was saved to <filename>%1</filename>", filename), i18nc("@title:window", "Save Secret Team Key"));
+
+ finished();
+}
+
+void ExportSecretTeamKeyCommand::Private::showError(const Error &err, const AuditLogEntry &auditLog)
+{
+ error(xi18nc("@info",
+ "<para>An error occurred during the saving of the secret team key:</para>"
+ "<para><message>%1</message></para>",
+ Formatting::errorAsString(err)),
+ auditLog);
+}
+
+ExportSecretTeamKeyCommand::ExportSecretTeamKeyCommand(QAbstractItemView *view, KeyListController *controller)
+ : Command{view, new Private{this, controller}}
+{
+}
+
+ExportSecretTeamKeyCommand::ExportSecretTeamKeyCommand(const GpgME::Key &key)
+ : Command{key, new Private{this}}
+{
+}
+
+ExportSecretTeamKeyCommand::~ExportSecretTeamKeyCommand() = default;
+
+void ExportSecretTeamKeyCommand::doStart()
+{
+ d->start();
+}
+
+void ExportSecretTeamKeyCommand::doCancel()
+{
+ d->cancel();
+}
+
+void ExportSecretTeamKeyCommand::Private::prepareExport(bool sign)
+{
+ const Key key = this->key();
+
+ filename = requestFilename(proposeFilename(key), parentWidgetOrView());
+ if (filename.isEmpty()) {
+ canceled();
+ return;
+ }
+
+ auto exportJob = startExportJob(key, sign);
+ if (!exportJob) {
+ finished();
+ return;
+ }
+ job = exportJob.release();
+}
+
+#undef d
+#undef q
+
+#include "moc_exportsecretteamkeycommand.cpp"
diff --git a/src/commands/exportsecretteamkeycommand.h b/src/commands/exportsecretteamkeycommand.h
new file mode 100644
index 000000000..47bbcaa82
--- /dev/null
+++ b/src/commands/exportsecretteamkeycommand.h
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: 2025 g10 Code GmbH
+// SPDX-FileContributor: Tobias Fella <tobias.fella@gnupg.com>
+// SPDX-License-Identifier: LGPL-2.0-or-later
+
+#pragma once
+
+#include "command.h"
+
+namespace Kleo
+{
+namespace Commands
+{
+
+class ExportSecretTeamKeyCommand : public Command
+{
+ Q_OBJECT
+public:
+ explicit ExportSecretTeamKeyCommand(QAbstractItemView *view, KeyListController *parent);
+ explicit ExportSecretTeamKeyCommand(const GpgME::Key &key);
+ ~ExportSecretTeamKeyCommand() override;
+
+ /* reimp */ static Restrictions restrictions()
+ {
+ return OnlyOneKey | NeedSecretKey /* We only want the owner to export the key */ | MustBeOpenPGP | NeedSecretEncryptSubkey;
+ }
+
+private:
+ void doStart() override;
+ void doCancel() override;
+
+private:
+ class Private;
+ inline Private *d_func();
+ inline const Private *d_func() const;
+};
+
+}
+}
diff --git a/src/kleopatra.rc b/src/kleopatra.rc
index 9ad6bf23b..2d03d375c 100644
--- a/src/kleopatra.rc
+++ b/src/kleopatra.rc
@@ -1,150 +1,151 @@
<!DOCTYPE gui >
-<gui name="kleopatra" version="527" >
+<gui name="kleopatra" version="528" >
<MenuBar>
<Menu name="file">
<text>&amp;File</text>
<Action name="file_new_certificate"/>
<Action name="file_new_certificate_signing_request"/>
<Separator/>
<Action name="file_lookup_certificates"/>
<Action name="file_import_certificates"/>
<Separator/>
<Action name="file_export_certificates"/>
<Action name="file_export_secret_keys"/>
+ <Action name="file_export_secret_team_key"/>
<Action name="file_export_paper_key"/>
<Action name="file_export_certificates_to_server"/>
<Action name="file_export_certificate_to_provider"/>
<Separator/>
<Action name="file_decrypt_verify_files"/>
<Action name="file_sign_encrypt_files"/>
<Action name="file_sign_encrypt_folder"/>
<Separator/>
<Action name="file_checksum_create_files"/>
<Action name="file_checksum_verify_files"/>
<Separator/>
<Action name="quit" />
</Menu>
<Menu name="certMenu">
<text>&amp;Certificates</text>
<Action name="view_certificate_details"/>
<Separator/>
<Action name="certificates_refresh"/>
<Separator/>
<Action name="certificates_change_owner_trust"/>
<Action name="certificates_disable"/>
<Action name="certificates_trust_root"/>
<Action name="certificates_distrust_root"/>
<Separator/>
<Action name="certificates_certify_certificate"/>
<Action name="certificates_revoke_certification"/>
<Separator/>
<Action name="certificates_change_expiry"/>
<Action name="certificates_change_passphrase"/>
<Action name="certificates_add_userid"/>
<Separator/>
<Action name="certificates_revoke"/>
<Action name="certificates_delete"/>
<Separator/>
<Action name="certificates_create_group"/>
<Separator/>
<Action name="certificate_to_card"/>
</Menu>
<Menu name="_tools">
<text>&amp;Tools</text>
<Action name="settings_self_test"/>
<Action name="tools_start_kwatchgnupg"/>
<Action name="tools_debug_view"/>
<Separator/>
<Action name="pad_view"/>
<Action name="manage_smartcard"/>
<Separator/>
<Action name="configure_groups"/>
<Separator/>
<Action name="clipboard_menu"/>
<Separator/>
<Action name="crl_import_crl"/>
<Separator/>
<Action name="crl_clear_crl_cache"/>
<Action name="crl_dump_crl_cache"/>
<Separator/>
<Action name="tools_restart_backend"/>
</Menu>
<Menu name="_view">
<text>&amp;View</text>
<Action name="reload_certificate_list"/>
<Separator/>
<Action name="window_view_hierarchical"/>
<Separator/>
<Action name="window_expand_all"/>
<Action name="window_collapse_all"/>
<Action name="columns_menu"/>
<Action name="columns_sort_menu"/>
</Menu>
<Menu name="settings">
<text>&amp;Settings</text>
<Action name="colorscheme_menu" group="show_merge"/>
</Menu>
<Menu name="help">
<text>&amp;Help</text>
<Action name="help_doc_quickguide"/>
<Action name="help_doc_symenc"/>
<Action name="help_doc_groups"/>
<Action name="help_doc_gpgol"/>
<Action name="help_doc_compendium"/>
<Menu name="help_more">
<text>&amp;More Documentation</text>
<Action name="help_doc_cert_management"/>
<Action name="help_doc_smartcard"/>
<Action name="help_doc_gnupg"/>
</Menu>
<Separator/>
<Action name="help_doc_approval_manual"/>
<Action name="help_doc_vsa"/>
<Separator/>
<Action name="help_check_updates"/>
</Menu>
</MenuBar>
<ToolBar fullWidth="false" name="mainToolBar" iconText="TextUnderIcon">
<text>Main Toolbar</text>
<Action name="file_sign_encrypt_files"/>
<Action name="file_decrypt_verify_files"/>
<Separator/>
<Action name="file_import_certificates"/>
<Action name="file_export_certificates"/>
<Action name="certificates_certify_certificate"/>
<Action name="file_lookup_certificates"/>
<Separator/>
<Action name="pad_view"/>
<Action name="manage_smartcard"/>
<Separator/>
<Action name="configure_groups_toolbar"/>
</ToolBar>
<Menu name="listview_popup">
<text>&amp;Certificates</text>
<Action name="view_certificate_details"/>
<Separator/>
<Action name="certificates_refresh"/>
<Separator/>
<Action name="certificates_certify_certificate"/>
<Action name="certificates_revoke_certification"/>
<Action name="certificates_change_owner_trust"/>
<Action name="certificates_disable"/>
<Separator/>
<Action name="certificates_change_expiry"/>
<Action name="certificates_change_passphrase"/>
<Action name="certificates_add_userid"/>
<Separator/>
<Action name="certificates_revoke"/>
<Separator/>
<Action name="certificates_create_group"/>
<Separator/>
<Action name="file_export_certificates"/>
<Action name="file_export_secret_keys"/>
<Action name="file_export_certificates_to_server"/>
<Separator/>
<Action name="cell_copy"/>
</Menu>
</gui>
diff --git a/src/view/keylistcontroller.cpp b/src/view/keylistcontroller.cpp
index 5bb48ea7c..ebc13526e 100644
--- a/src/view/keylistcontroller.cpp
+++ b/src/view/keylistcontroller.cpp
@@ -1,1107 +1,1126 @@
/*
This file is part of Kleopatra, the KDE keymanager
SPDX-FileCopyrightText: 2007 Klarälvdalens Datakonsult AB
SPDX-FileCopyrightText: 2022 Felix Tiede
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <config-kleopatra.h>
#include "keylistcontroller.h"
#include "tabwidget.h"
#include <smartcard/readerstatus.h>
#include <utils/action_data.h>
#include "commands/exportcertificatecommand.h"
#include "commands/exportopenpgpcertstoservercommand.h"
#include "kleopatra_debug.h"
#include <settings.h>
#ifdef MAILAKONADI_ENABLED
#include "commands/exportopenpgpcerttoprovidercommand.h"
#endif // MAILAKONADI_ENABLED
#include "commands/adduseridcommand.h"
#include "commands/certificatetocardcommand.h"
#include "commands/certifycertificatecommand.h"
#include "commands/changeexpirycommand.h"
#include "commands/changeownertrustcommand.h"
#include "commands/changepassphrasecommand.h"
#include "commands/changeroottrustcommand.h"
#include "commands/checksumcreatefilescommand.h"
#include "commands/checksumverifyfilescommand.h"
#include "commands/clearcrlcachecommand.h"
#include "commands/creategroupcommand.h"
#include "commands/decryptverifyfilescommand.h"
#include "commands/deletecertificatescommand.h"
#include "commands/detailscommand.h"
#include "commands/dumpcertificatecommand.h"
#include "commands/dumpcrlcachecommand.h"
#include "commands/exportpaperkeycommand.h"
#include "commands/exportsecretkeycommand.h"
+#include "commands/exportsecretteamkeycommand.h"
#include "commands/importcertificatefromfilecommand.h"
#include "commands/importcrlcommand.h"
#include "commands/lookupcertificatescommand.h"
#include "commands/newcertificatesigningrequestcommand.h"
#include "commands/newopenpgpcertificatecommand.h"
#include "commands/refreshcertificatescommand.h"
#include "commands/reloadkeyscommand.h"
#include "commands/revokecertificationcommand.h"
#include "commands/revokekeycommand.h"
#include "commands/signencryptfilescommand.h"
#include "commands/signencryptfoldercommand.h"
#include "commands/togglecertificateenabledcommand.h"
#include <Libkleo/Algorithm>
#include <Libkleo/CryptoConfig>
#include <Libkleo/Formatting>
#include <Libkleo/GnuPG>
#include <Libkleo/KeyCache>
#include <Libkleo/KeyListModel>
#include <gpgme++/key.h>
#include <gpgme.h>
#include <KActionCollection>
#include <KLocalizedString>
#include <QAbstractItemView>
#include <QAction>
#include <QClipboard>
#include <QGuiApplication>
#include <QItemSelectionModel>
#include <QPointer>
#include <algorithm>
#include <iterator>
using namespace Kleo;
using namespace Kleo::Commands;
using namespace Kleo::SmartCard;
using namespace GpgME;
using namespace Qt::Literals::StringLiterals;
namespace ranges = std::ranges;
class KeyListController::Private
{
friend class ::Kleo::KeyListController;
KeyListController *const q;
public:
explicit Private(KeyListController *qq);
~Private();
void connectView(QAbstractItemView *view);
void connectCommand(Command *cmd);
void connectTabWidget();
void disconnectTabWidget();
void addCommand(Command *cmd)
{
connectCommand(cmd);
commands.insert(ranges::lower_bound(commands, cmd), cmd);
}
void addView(QAbstractItemView *view)
{
connectView(view);
views.insert(ranges::lower_bound(views, view), view);
}
void removeView(QAbstractItemView *view)
{
view->disconnect(q);
view->selectionModel()->disconnect(q);
std::erase(views, view);
}
public:
void slotDestroyed(QObject *o)
{
qCDebug(KLEOPATRA_LOG) << (void *)o;
std::erase(views, o);
std::erase(commands, o);
}
void slotActivated(const QModelIndex &idx);
void slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_);
void slotContextMenu(const QPoint &pos);
void slotCommandFinished();
void slotActionTriggered(QAction *action);
void slotCurrentViewChanged(QAbstractItemView *view)
{
if (view && !ranges::binary_search(views, view)) {
qCDebug(KLEOPATRA_LOG) << "you need to register view" << view << "before trying to set it as the current view!";
addView(view);
}
currentView = view;
q->enableDisableActions(view ? view->selectionModel() : nullptr);
}
void updateActions(KActionCollection *collection);
private:
int toolTipOptions() const;
private:
static Command::Restrictions calculateRestrictionsMask(const QItemSelectionModel *sm);
private:
struct action_item {
QPointer<QAction> action;
Command::Restrictions restrictions;
Command *(*createCommand)(QAbstractItemView *, KeyListController *);
};
std::vector<action_item> actions;
std::vector<QAbstractItemView *> views;
std::vector<Command *> commands;
QPointer<QWidget> parentWidget;
QPointer<TabWidget> tabWidget;
QPointer<QAbstractItemView> currentView;
QPointer<AbstractKeyListModel> flatModel, hierarchicalModel;
std::vector<QMetaObject::Connection> m_connections;
};
KeyListController::Private::Private(KeyListController *qq)
: q(qq)
, actions()
, views()
, commands()
, parentWidget()
, tabWidget()
, flatModel()
, hierarchicalModel()
{
}
KeyListController::Private::~Private()
{
}
KeyListController::KeyListController(QObject *p)
: QObject(p)
, d(new Private(this))
{
}
KeyListController::~KeyListController()
{
}
void KeyListController::addView(QAbstractItemView *view)
{
if (!view || ranges::binary_search(d->views, view)) {
return;
}
d->addView(view);
}
void KeyListController::removeView(QAbstractItemView *view)
{
if (!view || !ranges::binary_search(d->views, view)) {
return;
}
d->removeView(view);
}
void KeyListController::setCurrentView(QAbstractItemView *view)
{
d->slotCurrentViewChanged(view);
}
std::vector<QAbstractItemView *> KeyListController::views() const
{
return d->views;
}
void KeyListController::setFlatModel(AbstractKeyListModel *model)
{
if (model == d->flatModel) {
return;
}
d->flatModel = model;
if (model) {
model->setToolTipOptions(d->toolTipOptions());
}
}
void KeyListController::setHierarchicalModel(AbstractKeyListModel *model)
{
if (model == d->hierarchicalModel) {
return;
}
d->hierarchicalModel = model;
if (model) {
model->setToolTipOptions(d->toolTipOptions());
}
}
void KeyListController::setTabWidget(TabWidget *tabWidget)
{
if (tabWidget == d->tabWidget) {
return;
}
d->disconnectTabWidget();
d->tabWidget = tabWidget;
d->connectTabWidget();
d->slotCurrentViewChanged(tabWidget ? tabWidget->currentView() : nullptr);
}
void KeyListController::setParentWidget(QWidget *parent)
{
d->parentWidget = parent;
}
QWidget *KeyListController::parentWidget() const
{
return d->parentWidget;
}
void KeyListController::Private::connectTabWidget()
{
if (!tabWidget) {
return;
}
const auto views = tabWidget->views();
ranges::for_each(views, [this](QAbstractItemView *view) {
addView(view);
});
m_connections.reserve(3);
m_connections.push_back(connect(tabWidget, &TabWidget::viewAdded, q, &KeyListController::addView));
m_connections.push_back(connect(tabWidget, &TabWidget::viewAboutToBeRemoved, q, &KeyListController::removeView));
m_connections.push_back(connect(tabWidget, &TabWidget::currentViewChanged, q, [this](QAbstractItemView *view) {
slotCurrentViewChanged(view);
}));
}
void KeyListController::Private::disconnectTabWidget()
{
if (!tabWidget) {
return;
}
for (const auto &connection : m_connections) {
disconnect(connection);
}
m_connections.clear();
const auto views = tabWidget->views();
ranges::for_each(views, [this](QAbstractItemView *view) {
removeView(view);
});
}
AbstractKeyListModel *KeyListController::flatModel() const
{
return d->flatModel;
}
AbstractKeyListModel *KeyListController::hierarchicalModel() const
{
return d->hierarchicalModel;
}
QAbstractItemView *KeyListController::currentView() const
{
return d->currentView;
}
TabWidget *KeyListController::tabWidget() const
{
return d->tabWidget;
}
void KeyListController::createActions(KActionCollection *coll)
{
std::vector<action_data> common_and_openpgp_action_data = {
// File menu
{
"file_new_certificate",
i18n("New OpenPGP Key Pair..."),
i18n("Create a new OpenPGP certificate"),
"view-certificate-add",
nullptr,
nullptr,
QStringLiteral("Ctrl+N"),
},
{
"file_export_certificates",
i18n("Export..."),
i18n("Export the selected certificate (public key) to a file"),
"view-certificate-export",
nullptr,
nullptr,
QStringLiteral("Ctrl+E"),
},
{
"file_export_certificates_to_server",
i18n("Publish on Server..."),
keyserver().startsWith(QStringLiteral("ldap:")) || keyserver().startsWith(QStringLiteral("ldaps:"))
? i18n("Publish the selected certificate (public key) to internal directory")
: i18n("Publish the selected certificate (public key) on %1", keyserver()),
"view-certificate-export-server",
nullptr,
nullptr,
QStringLiteral("Ctrl+Shift+E"),
},
#ifdef MAILAKONADI_ENABLED
{
"file_export_certificate_to_provider",
i18n("Publish at Mail Provider..."),
i18n("Publish the selected certificate (public key) at mail provider's Web Key Directory if offered"),
"view-certificate-export",
nullptr,
nullptr,
QString(),
},
#endif // MAILAKONADI_ENABLED
{
"file_export_secret_keys",
i18n("Backup Secret Keys..."),
QString(),
"view-certificate-export-secret",
nullptr,
nullptr,
QString(),
},
+ {
+ "file_export_secret_team_key",
+ i18nc("@action:inmenu", "Save Secret Team Key..."),
+ QString(),
+ "view-certificate-export-secret",
+ nullptr,
+ nullptr,
+ QString(),
+ },
{
"file_export_paper_key",
i18n("Print Secret Key..."),
QString(),
"document-print",
nullptr,
nullptr,
QString(),
},
{
"file_lookup_certificates",
i18n("Lookup on Server..."),
keyserver().startsWith(QStringLiteral("ldap:")) || keyserver().startsWith(QStringLiteral("ldaps:"))
? i18n("Search for certificates in internal directory")
: i18n("Search for certificates on %1", keyserver()),
"edit-find",
nullptr,
nullptr,
QStringLiteral("Shift+Ctrl+I"),
},
{
"file_import_certificates",
i18n("Import..."),
i18n("Import a certificate from a file"),
"view-certificate-import",
nullptr,
nullptr,
QStringLiteral("Ctrl+I"),
},
{
"file_decrypt_verify_files",
i18n("Decrypt/Verify..."),
i18n("Decrypt and/or verify files"),
"document-edit-decrypt-verify",
nullptr,
nullptr,
QString(),
},
{
"file_sign_encrypt_files",
i18n("Sign/Encrypt..."),
i18n("Encrypt and/or sign files"),
"document-edit-sign-encrypt",
nullptr,
nullptr,
QString(),
},
{
"file_sign_encrypt_folder",
i18n("Sign/Encrypt Folder..."),
i18n("Encrypt and/or sign folders"),
"folder-edit-sign-encrypt-symbolic",
nullptr,
nullptr,
QString(),
},
{
"file_checksum_create_files",
i18n("Create Checksum Files..."),
QString(),
nullptr /*"document-checksum-create"*/,
nullptr,
nullptr,
QString(),
},
{
"file_checksum_verify_files",
i18n("Verify Checksum Files..."),
QString(),
nullptr /*"document-checksum-verify"*/,
nullptr,
nullptr,
QString(),
},
{
"view_certificate_details",
i18n("Details"),
QString(),
"info",
nullptr,
nullptr,
QString(),
},
// Certificate menu
{
"certificates_revoke",
i18n("Revoke Certificate..."),
i18n("Revoke the selected OpenPGP certificate"),
"view-certificate-revoke",
nullptr,
nullptr,
{},
},
{
"certificates_delete",
i18n("Delete"),
i18n("Delete selected certificates"),
"edit-delete",
nullptr,
nullptr,
QStringLiteral("Delete"),
},
{
"certificates_refresh",
i18n("Update Certificates"),
i18n("Update selected certificates"),
"view-refresh",
nullptr,
nullptr,
QString(),
},
{
"certificates_certify_certificate",
i18n("Certify..."),
i18n("Certify the validity of the selected certificate"),
"view-certificate-sign",
nullptr,
nullptr,
QString(),
},
{
"certificates_revoke_certification",
i18n("Revoke Certification..."),
i18n("Revoke the certification of the selected certificate"),
"view-certificate-revoke",
nullptr,
nullptr,
QString(),
},
{
"certificates_change_expiry",
i18n("Change End of Validity Period..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_change_owner_trust",
i18nc("@action:inmenu", "Change Certification Power..."),
i18nc("@info:tooltip", "Grant or revoke the certification power of the selected certificate"),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_change_passphrase",
i18n("Change Passphrase..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_add_userid",
i18n("Add User ID..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"certificates_create_group",
i18nc("@action:inmenu", "Create Group..."),
i18nc("@info:tooltip", "Create a group from the selected certificates"),
"resource-group-new",
nullptr,
nullptr,
QString(),
},
{
"certificate_to_card",
i18nc("@action:inmenu", "Copy to Card"),
i18nc("@info:tooltip", "Copy the selected certificate to a smartcard"),
"auth-sim-locked",
nullptr,
nullptr,
QString(),
},
// View menu
{
"reload_certificate_list",
i18n("Redisplay"),
QString(),
"view-refresh",
nullptr,
nullptr,
QStringLiteral("F5"),
},
// Context Menu
{
"cell_copy",
i18nc("@action:button", "Copy"),
QString(),
"edit-copy",
this,
[this](bool) {
QGuiApplication::clipboard()->setText(currentView()->currentIndex().data(Kleo::ClipboardRole).toString());
},
QStringLiteral("Ctrl+C"),
}
// Window menu
// (come from TabWidget)
// Help menu
// (come from MainWindow)
};
if (ToggleCertificateEnabledCommand::isSupported()) {
common_and_openpgp_action_data.emplace_back(
"certificates_disable",
i18nc("@action:inmenu", "Disable Certificate"),
"<html>"_L1
+ i18nc("@action:tooltip",
"Disabled certificates are not offered when selecting a certificate to sign with or to encrypt for. They are not "
"shown in the certificate list with most filters.")
+ "</html>"_L1,
nullptr,
nullptr,
nullptr,
QString());
}
static const action_data cms_create_csr_action_data = {
"file_new_certificate_signing_request",
i18n("New S/MIME Certification Request..."),
i18n("Create a new S/MIME certificate signing request (CSR)"),
"view-certificate-add",
nullptr,
nullptr,
{},
};
static const action_data certificates_trust_root_action_data = {
"certificates_trust_root",
i18n("Trust Root Certificate"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
};
static const action_data certificates_distrust_root_action_data = {
"certificates_distrust_root",
i18n("Distrust Root Certificate"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
};
static const std::vector<action_data> cms_action_data = {
{
"certificates_dump_certificate",
i18n("Technical Details"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"crl_clear_crl_cache",
i18n("Clear CRL Cache"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"crl_dump_crl_cache",
i18n("Dump CRL Cache"),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
{
"crl_import_crl",
i18n("Import CRL From File..."),
QString(),
nullptr,
nullptr,
nullptr,
QString(),
},
};
std::vector<action_data> action_data = common_and_openpgp_action_data;
if (const Kleo::Settings settings{}; settings.cmsEnabled()) {
action_data.reserve(action_data.size() + 3 + cms_action_data.size());
if (settings.cmsCertificateCreationAllowed()) {
action_data.push_back(cms_create_csr_action_data);
}
if (!getCryptoConfigBoolValue("gpg-agent", "no-allow-mark-trusted")) {
// user is allowed to mark certificates as trusted or not trusted
action_data.push_back(certificates_trust_root_action_data);
action_data.push_back(certificates_distrust_root_action_data);
}
ranges::copy(cms_action_data, std::back_inserter(action_data));
}
make_actions_from_data(action_data, coll);
if (QAction *action = coll->action(QStringLiteral("view_stop_operations"))) {
connect(this, &KeyListController::commandsExecuting, action, &QAction::setEnabled);
}
// ### somehow make this better...
registerActionForCommand<NewOpenPGPCertificateCommand>(coll->action(QStringLiteral("file_new_certificate")));
registerActionForCommand<NewCertificateSigningRequestCommand>(coll->action(QStringLiteral("file_new_certificate_signing_request")));
//---
registerActionForCommand<LookupCertificatesCommand>(coll->action(QStringLiteral("file_lookup_certificates")));
registerActionForCommand<ImportCertificateFromFileCommand>(coll->action(QStringLiteral("file_import_certificates")));
//---
registerActionForCommand<ExportCertificateCommand>(coll->action(QStringLiteral("file_export_certificates")));
registerActionForCommand<ExportSecretKeyCommand>(coll->action(QStringLiteral("file_export_secret_keys")));
+ registerActionForCommand<ExportSecretTeamKeyCommand>(coll->action(QStringLiteral("file_export_secret_team_key")));
registerActionForCommand<ExportPaperKeyCommand>(coll->action(QStringLiteral("file_export_paper_key")));
registerActionForCommand<ExportOpenPGPCertsToServerCommand>(coll->action(QStringLiteral("file_export_certificates_to_server")));
#ifdef MAILAKONADI_ENABLED
registerActionForCommand<ExportOpenPGPCertToProviderCommand>(coll->action(QStringLiteral("file_export_certificate_to_provider")));
#endif // MAILAKONADI_ENABLED
registerActionForCommand<CertificateToCardCommand>(coll->action(QStringLiteral("certificate_to_card")));
//---
registerActionForCommand<DecryptVerifyFilesCommand>(coll->action(QStringLiteral("file_decrypt_verify_files")));
registerActionForCommand<SignEncryptFilesCommand>(coll->action(QStringLiteral("file_sign_encrypt_files")));
registerActionForCommand<SignEncryptFolderCommand>(coll->action(QStringLiteral("file_sign_encrypt_folder")));
//---
registerActionForCommand<ChecksumCreateFilesCommand>(coll->action(QStringLiteral("file_checksum_create_files")));
registerActionForCommand<ChecksumVerifyFilesCommand>(coll->action(QStringLiteral("file_checksum_verify_files")));
registerActionForCommand<ReloadKeysCommand>(coll->action(QStringLiteral("reload_certificate_list")));
// coll->action( "view_stop_operations" ) <-- already dealt with in make_actions_from_data()
registerActionForCommand<DetailsCommand>(coll->action(QStringLiteral("view_certificate_details")));
registerActionForCommand<ChangeOwnerTrustCommand>(coll->action(QStringLiteral("certificates_change_owner_trust")));
if (auto action = coll->action(QStringLiteral("certificates_trust_root"))) {
registerActionForCommand<TrustRootCommand>(action);
}
if (auto action = coll->action(QStringLiteral("certificates_distrust_root"))) {
registerActionForCommand<DistrustRootCommand>(action);
}
if (ToggleCertificateEnabledCommand::isSupported()) {
registerActionForCommand<ToggleCertificateEnabledCommand>(coll->action(QStringLiteral("certificates_disable")));
}
//---
registerActionForCommand<CertifyCertificateCommand>(coll->action(QStringLiteral("certificates_certify_certificate")));
if (RevokeCertificationCommand::isSupported()) {
registerActionForCommand<RevokeCertificationCommand>(coll->action(QStringLiteral("certificates_revoke_certification")));
}
//---
registerActionForCommand<ChangeExpiryCommand>(coll->action(QStringLiteral("certificates_change_expiry")));
registerActionForCommand<ChangePassphraseCommand>(coll->action(QStringLiteral("certificates_change_passphrase")));
registerActionForCommand<AddUserIDCommand>(coll->action(QStringLiteral("certificates_add_userid")));
registerActionForCommand<CreateGroupCommand>(coll->action(QStringLiteral("certificates_create_group")));
//---
registerActionForCommand<RevokeKeyCommand>(coll->action(QStringLiteral("certificates_revoke")));
registerActionForCommand<DeleteCertificatesCommand>(coll->action(QStringLiteral("certificates_delete")));
//---
registerActionForCommand<RefreshCertificatesCommand>(coll->action(QStringLiteral("certificates_refresh")));
//---
registerActionForCommand<DumpCertificateCommand>(coll->action(QStringLiteral("certificates_dump_certificate")));
//---
registerActionForCommand<ImportCrlCommand>(coll->action(QStringLiteral("crl_import_crl")));
//---
registerActionForCommand<ClearCrlCacheCommand>(coll->action(QStringLiteral("crl_clear_crl_cache")));
registerActionForCommand<DumpCrlCacheCommand>(coll->action(QStringLiteral("crl_dump_crl_cache")));
enableDisableActions(nullptr);
connect(KeyCache::instance().get(), &KeyCache::keysMayHaveChanged, this, [this, coll]() {
d->updateActions(coll);
});
connect(this, &KeyListController::selectionChanged, this, [coll, this]() {
d->updateActions(coll);
});
}
void KeyListController::registerAction(QAction *action, Command::Restrictions restrictions, Command *(*create)(QAbstractItemView *, KeyListController *))
{
if (!action) {
return;
}
Q_ASSERT(!action->isCheckable()); // can be added later, for now, disallow
const Private::action_item ai = {action, restrictions, create};
connect(action, &QAction::triggered, this, [this, action]() {
d->slotActionTriggered(action);
});
d->actions.push_back(ai);
}
void KeyListController::registerCommand(Command *cmd)
{
if (!cmd || ranges::binary_search(d->commands, cmd)) {
return;
}
d->addCommand(cmd);
qCDebug(KLEOPATRA_LOG) << (void *)cmd;
if (d->commands.size() == 1) {
Q_EMIT commandsExecuting(true);
}
}
bool KeyListController::hasRunningCommands() const
{
return !d->commands.empty();
}
bool KeyListController::shutdownWarningRequired() const
{
return ranges::any_of(d->commands, std::mem_fn(&Command::warnWhenRunningAtShutdown));
}
// slot
void KeyListController::cancelCommands()
{
ranges::for_each(d->commands, std::mem_fn(&Command::cancel));
}
void KeyListController::Private::connectView(QAbstractItemView *view)
{
connect(view, &QObject::destroyed, q, [this](QObject *obj) {
slotDestroyed(obj);
});
connect(view, &QAbstractItemView::activated, q, [this](const QModelIndex &index) {
slotActivated(index);
});
connect(view->selectionModel(), &QItemSelectionModel::selectionChanged, q, [this](const QItemSelection &oldSel, const QItemSelection &newSel) {
slotSelectionChanged(oldSel, newSel);
Q_EMIT q->selectionChanged();
});
view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(view, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) {
slotContextMenu(pos);
});
}
void KeyListController::Private::connectCommand(Command *cmd)
{
if (!cmd) {
return;
}
connect(cmd, &QObject::destroyed, q, [this](QObject *obj) {
slotDestroyed(obj);
});
connect(cmd, &Command::finished, q, [this] {
slotCommandFinished();
});
// connect( cmd, SIGNAL(canceled()), q, SLOT(slotCommandCanceled()) );
connect(cmd, &Command::progress, q, &KeyListController::progress);
}
void KeyListController::Private::slotActivated(const QModelIndex &idx)
{
QAbstractItemView *const view = qobject_cast<QAbstractItemView *>(q->sender());
if (!view || !ranges::binary_search(views, view)) {
return;
}
if (const auto *const keyListModel = dynamic_cast<KeyListModelInterface *>(view->model())) {
DetailsCommand *const c = new DetailsCommand{keyListModel->key(idx)};
c->setParentWidget(parentWidget ? parentWidget : view);
c->start();
}
}
void KeyListController::Private::slotSelectionChanged(const QItemSelection &old, const QItemSelection &new_)
{
Q_UNUSED(old)
Q_UNUSED(new_)
const QItemSelectionModel *const sm = qobject_cast<QItemSelectionModel *>(q->sender());
if (!sm) {
return;
}
q->enableDisableActions(sm);
}
void KeyListController::Private::slotContextMenu(const QPoint &p)
{
QAbstractItemView *const view = qobject_cast<QAbstractItemView *>(q->sender());
if (view && ranges::binary_search(views, view)) {
Q_EMIT q->contextMenuRequested(view, view->viewport()->mapToGlobal(p));
} else {
qCDebug(KLEOPATRA_LOG) << "sender is not a QAbstractItemView*!";
}
}
void KeyListController::Private::slotCommandFinished()
{
Command *const cmd = qobject_cast<Command *>(q->sender());
if (!cmd || !ranges::binary_search(commands, cmd)) {
return;
}
qCDebug(KLEOPATRA_LOG) << (void *)cmd;
if (commands.size() == 1) {
Q_EMIT q->commandsExecuting(false);
}
}
void KeyListController::enableDisableActions(const QItemSelectionModel *sm) const
{
const Command::Restrictions restrictionsMask = d->calculateRestrictionsMask(sm);
for (const Private::action_item &ai : std::as_const(d->actions))
if (ai.action) {
ai.action->setEnabled(ai.restrictions == (ai.restrictions & restrictionsMask));
}
}
static bool all_secret_are_not_owner_trust_ultimate(const std::vector<Key> &keys)
{
for (const Key &key : keys)
if (key.hasSecret() && key.ownerTrust() == Key::Ultimate) {
return false;
}
return true;
}
Command::Restrictions find_root_restrictions(const std::vector<Key> &keys)
{
bool trusted = false, untrusted = false;
for (const Key &key : keys)
if (key.isRoot())
if (key.userID(0).validity() == UserID::Ultimate) {
trusted = true;
} else {
untrusted = true;
}
else {
return Command::NoRestriction;
}
if (trusted)
if (untrusted) {
return Command::NoRestriction;
} else {
return Command::MustBeTrustedRoot;
}
else if (untrusted) {
return Command::MustBeUntrustedRoot;
} else {
return Command::NoRestriction;
}
}
static bool secretSubkeyDataAvailable(const Subkey &subkey)
{
return subkey.isSecret() && !subkey.isCardKey();
}
Command::Restrictions KeyListController::Private::calculateRestrictionsMask(const QItemSelectionModel *sm)
{
if (!sm) {
return Command::NoRestriction;
}
const KeyListModelInterface *const m = dynamic_cast<const KeyListModelInterface *>(sm->model());
if (!m) {
return Command::NoRestriction;
}
const std::vector<Key> keys = m->keys(sm->selectedRows());
if (keys.empty()) {
return Command::NoRestriction;
}
Command::Restrictions result = Command::NeedSelection;
if (keys.size() == 1) {
result |= Command::OnlyOneKey;
}
// we need to check the primary subkey because Key::hasSecret() is also true if just the secret key stub of an offline key is available
const auto primaryKeyCanBeUsedForSecretKeyOperations = [](const auto &k) {
return k.subkey(0).isSecret();
};
if (ranges::all_of(keys, primaryKeyCanBeUsedForSecretKeyOperations)) {
result |= Command::NeedSecretKey;
}
if (ranges::all_of(keys, [](const auto &k) {
return ranges::any_of(k.subkeys(), &secretSubkeyDataAvailable);
})) {
result |= Command::NeedSecretSubkeyData;
}
if ((result & Command::NeedSecretSubkeyData) && ranges::all_of(keys, [](const auto &k) {
return secretSubkeyDataAvailable(k.subkey(0));
})) {
result |= Command::NeedSecretPrimaryKeyData;
}
if (ranges::all_of(keys, [](const Key &key) {
return key.protocol() == OpenPGP;
})) {
result |= Command::MustBeOpenPGP;
} else if (ranges::all_of(keys, [](const Key &key) {
return key.protocol() == CMS;
})) {
result |= Command::MustBeCMS;
}
if (ranges::all_of(keys, [](const auto &key) {
return !key.isBad();
})) {
result |= Command::MustBeValid;
}
if (all_secret_are_not_owner_trust_ultimate(keys)) {
result |= Command::MayOnlyBeSecretKeyIfOwnerTrustIsNotYetUltimate;
}
result |= find_root_restrictions(keys);
if (const ReaderStatus *rs = ReaderStatus::instance()) {
if (!rs->firstCardWithNullPin().empty()) {
result |= Command::AnyCardHasNullPin;
}
}
{
if (keys.size() > 0) {
bool hasSignCertify = false;
bool hasEncrypt = false;
bool hasAuthenticate = false;
bool invalid = false;
for (const auto &subkey : keys[0].subkeys()) {
if (subkey.isCardKey()) {
invalid = true;
break;
}
if (subkey.canCertify() && subkey.canSign()) {
if (hasSignCertify) {
invalid = true;
break;
} else {
hasSignCertify = true;
}
} else if (subkey.canEncrypt()) {
if (hasEncrypt) {
invalid = true;
break;
} else {
hasEncrypt = true;
}
} else if (subkey.canAuthenticate()) {
if (hasAuthenticate) {
invalid = true;
break;
} else {
hasAuthenticate = true;
}
} else if (!subkey.canRenc()) { // we don't mind ADSKs
invalid = true;
break;
}
}
if (hasSignCertify && hasEncrypt && !invalid) {
result |= Command::SuitableForCard;
}
}
}
+ if (std::ranges::all_of(keys, [](const auto &key) {
+ return !key.isBad() && std::ranges::any_of(key.subkeys(), [](const auto &subkey) {
+ return subkey.canEncrypt() && !subkey.isBad() && subkey.isSecret();
+ });
+ })) {
+ result |= Command::NeedSecretEncryptSubkey;
+ }
+
return result;
}
void KeyListController::Private::slotActionTriggered(QAction *sender)
{
const auto it = ranges::find_if(actions, [sender](const action_item &item) {
return item.action == sender;
});
if (it != actions.end())
if (Command *const c = it->createCommand(this->currentView, q)) {
if (parentWidget) {
c->setParentWidget(parentWidget);
}
c->start();
} else
qCDebug(KLEOPATRA_LOG) << "createCommand() == NULL for action(?) \"" << qPrintable(sender->objectName()) << "\"";
else {
qCDebug(KLEOPATRA_LOG) << "I don't know anything about action(?) \"%s\"", qPrintable(sender->objectName());
}
}
int KeyListController::Private::toolTipOptions() const
{
using namespace Kleo::Formatting;
static const int validityFlags = Validity | Issuer | ExpiryDates | CertificateUsage;
static const int ownerFlags = Subject | UserIDs | OwnerTrust;
static const int detailsFlags = StorageLocation | CertificateType | SerialNumber | Fingerprint;
const Settings settings;
int flags = KeyID;
flags |= settings.showValidity() ? validityFlags : 0;
flags |= settings.showOwnerInformation() ? ownerFlags : 0;
flags |= settings.showCertificateDetails() ? detailsFlags : 0;
return flags;
}
void KeyListController::updateConfig()
{
const int opts = d->toolTipOptions();
if (d->flatModel) {
d->flatModel->setToolTipOptions(opts);
}
if (d->hierarchicalModel) {
d->hierarchicalModel->setToolTipOptions(opts);
}
}
void KeyListController::Private::updateActions(KActionCollection *collection)
{
if (ToggleCertificateEnabledCommand::isSupported() && q->currentView()) {
auto key = q->currentView()->selectionModel()->currentIndex().data(KeyList::KeyRole).value<GpgME::Key>();
if (key.isNull() || !key.primaryFingerprint()) {
return;
}
// Get the key from the cache, as the existing one isn't correctly updated yet
key = KeyCache::instance()->findByKeyIDOrFingerprint(key.primaryFingerprint());
auto action = collection->action(QStringLiteral("certificates_disable"));
action->setText(key.isDisabled() ? i18nc("@action:inmenu", "Enable and Show Certificate") : i18nc("@action:inmenu", "Disable and Hide Certificate"));
}
}
#include "moc_keylistcontroller.cpp"

File Metadata

Mime Type
text/x-diff
Expires
Sun, Dec 28, 10:58 PM (1 d, 21 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
89/bc/f07eec0d133e08f9442c6ee3b889

Event Timeline