From 4e80563fabfdf1d1c136d65252e5353fdd1e9092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Tue, 4 Jan 2022 15:38:49 +0100 Subject: [PATCH] qt: Use QGpgMEExportJob also for export of secret keys * lang/qt/src/protocol.h (Protocol::secretKeyExportJob): Document charset argument as ignored. * lang/qt/src/protocol_p.h (Protocol::secretKeyExportJob): Use QGpgMEExportJob instead of QGpgMESecretKeyExportJob. * lang/qt/src/qgpgmeexportjob.h (class QGpgMEExportJob): Add c'tor taking an export mode. Add member m_exportMode. Rename member m_flags to m_additionalExportModeFlags. (QGpgMEExportJob::~QGpgMEExportJob): Mark as override. * lang/qt/src/qgpgmeexportjob.cpp (QGpgMEExportJob::QGpgMEExportJob): Delegate to new c'tor. Implement new c'tor. (QGpgMEExportJob::~QGpgMEExportJob): Use default. (export_qba): Rename argument flags to mode. (QGpgMEExportJob::start): Pass combination of export mode and additional mode flags to export_qba. (QGpgMEExportJob::setExportFlags): Adapt to renaming of member. * lang/qt/tests/run-exportjob.cpp: New. -- This change makes it possible to export secret OpenPGP keys. GnuPG-bug-id: 5757 --- lang/qt/src/protocol.h | 4 +- lang/qt/src/protocol_p.h | 12 ++-- lang/qt/src/qgpgmeexportjob.cpp | 24 ++++--- lang/qt/src/qgpgmeexportjob.h | 14 +++- lang/qt/tests/Makefile.am | 4 +- lang/qt/tests/run-exportjob.cpp | 113 ++++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 lang/qt/tests/run-exportjob.cpp diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index cffd53b2..35789414 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -126,8 +126,8 @@ public: virtual ImportJob *importJob() const = 0; virtual ImportFromKeyserverJob *importFromKeyserverJob() const = 0; virtual ExportJob *publicKeyExportJob(bool armor = false) const = 0; - // @param charset the encoding of the passphrase in the exported file - virtual ExportJob *secretKeyExportJob(bool armor = false, const QString &charset = QString()) const = 0; + // the second parameter is ignored; the passphrase in the exported file is always utf-8 encoded + virtual ExportJob *secretKeyExportJob(bool armor = false, const QString & = QString()) const = 0; virtual DownloadJob *downloadJob(bool armor = false) const = 0; virtual DeleteJob *deleteJob() const = 0; virtual SignEncryptJob *signEncryptJob(bool armor = false, bool textMode = false) const = 0; diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h index da5ce011..054fec6e 100644 --- a/lang/qt/src/protocol_p.h +++ b/lang/qt/src/protocol_p.h @@ -5,6 +5,8 @@ Copyright (c) 2004,2005 Klarälvdalens Datakonsult AB Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH + Copyright (c) 2022 by g10 Code GmbH + Software engineering by Ingo Klöcker QGpgME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -42,7 +44,6 @@ #include "qgpgmedecryptverifyjob.h" #include "qgpgmerefreshkeysjob.h" #include "qgpgmedeletejob.h" -#include "qgpgmesecretkeyexportjob.h" #include "qgpgmedownloadjob.h" #include "qgpgmesignencryptjob.h" #include "qgpgmeencryptjob.h" @@ -242,14 +243,15 @@ public: return new QGpgME::QGpgMEExportJob(context); } - QGpgME::ExportJob *secretKeyExportJob(bool armor, const QString &charset) const Q_DECL_OVERRIDE + QGpgME::ExportJob *secretKeyExportJob(bool armor, const QString &) const Q_DECL_OVERRIDE { - if (mProtocol != GpgME::CMS) { // fixme: add support for gpg, too + GpgME::Context *context = GpgME::Context::createForProtocol(mProtocol); + if (!context) { return nullptr; } - // this operation is not supported by gpgme, so we have to call gpgsm ourselves: - return new QGpgME::QGpgMESecretKeyExportJob(armor, charset); + context->setArmor(armor); + return new QGpgME::QGpgMEExportJob(context, GpgME::Context::ExportSecret); } QGpgME::RefreshKeysJob *refreshKeysJob() const Q_DECL_OVERRIDE diff --git a/lang/qt/src/qgpgmeexportjob.cpp b/lang/qt/src/qgpgmeexportjob.cpp index bf3297a7..e9bc0a4d 100644 --- a/lang/qt/src/qgpgmeexportjob.cpp +++ b/lang/qt/src/qgpgmeexportjob.cpp @@ -5,6 +5,8 @@ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH + Copyright (c) 2022 by g10 Code GmbH + Software engineering by Ingo Klöcker QGpgME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -52,23 +54,28 @@ using namespace QGpgME; using namespace GpgME; QGpgMEExportJob::QGpgMEExportJob(Context *context) - : mixin_type(context), - m_flags(0) + : QGpgMEExportJob{context, 0} +{ +} + +QGpgMEExportJob::QGpgMEExportJob(Context *context, unsigned int forcedMode) + : mixin_type{context} + , m_exportMode{forcedMode} + , m_additionalExportModeFlags{0} { lateInitialization(); } -QGpgMEExportJob::~QGpgMEExportJob() {} +QGpgMEExportJob::~QGpgMEExportJob() = default; -static QGpgMEExportJob::result_type export_qba(Context *ctx, const QStringList &patterns, unsigned int flags) +static QGpgMEExportJob::result_type export_qba(Context *ctx, const QStringList &patterns, unsigned int mode) { - const _detail::PatternConverter pc(patterns); QGpgME::QByteArrayDataProvider dp; Data data(&dp); - const Error err = ctx->exportPublicKeys(pc.patterns(), data, flags); + const Error err = ctx->exportKeys(pc.patterns(), data, mode); Error ae; const QString log = _detail::audit_log_as_html(ctx, ae); return std::make_tuple(err, dp.data(), log, ae); @@ -76,13 +83,14 @@ static QGpgMEExportJob::result_type export_qba(Context *ctx, const QStringList & Error QGpgMEExportJob::start(const QStringList &patterns) { - run(std::bind(&export_qba, std::placeholders::_1, patterns, m_flags)); + auto mode = m_exportMode | m_additionalExportModeFlags; + run(std::bind(&export_qba, std::placeholders::_1, patterns, mode)); return Error(); } void QGpgMEExportJob::setExportFlags(unsigned int flags) { - m_flags = flags; + m_additionalExportModeFlags = flags; } /* For ABI compat not pure virtual. */ diff --git a/lang/qt/src/qgpgmeexportjob.h b/lang/qt/src/qgpgmeexportjob.h index 3f6bd0e2..b77bad1c 100644 --- a/lang/qt/src/qgpgmeexportjob.h +++ b/lang/qt/src/qgpgmeexportjob.h @@ -5,6 +5,8 @@ Copyright (c) 2004,2008 Klarälvdalens Datakonsult AB Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik Software engineering by Intevation GmbH + Copyright (c) 2022 by g10 Code GmbH + Software engineering by Ingo Klöcker QGpgME is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -56,15 +58,21 @@ public Q_SLOTS: #endif public: explicit QGpgMEExportJob(GpgME::Context *context); - ~QGpgMEExportJob(); + // Creates an export job with forced export mode @p exportMode. The + // export mode flags set with @p exportMode cannot be overridden with + // setExportFlags. + explicit QGpgMEExportJob(GpgME::Context *context, unsigned int exportMode); + ~QGpgMEExportJob() Q_DECL_OVERRIDE; /* from ExportJob */ - void setExportFlags (unsigned int flags) Q_DECL_OVERRIDE; + void setExportFlags(unsigned int flags) Q_DECL_OVERRIDE; /* from ExportJob */ GpgME::Error start(const QStringList &patterns) Q_DECL_OVERRIDE; + private: - unsigned int m_flags; + unsigned int m_exportMode; + unsigned int m_additionalExportModeFlags; }; } diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am index ef67a637..57ae59af 100644 --- a/lang/qt/tests/Makefile.am +++ b/lang/qt/tests/Makefile.am @@ -66,6 +66,7 @@ t_trustsignatures_SOURCES = t-trustsignatures.cpp $(support_src) t_changeexpiryjob_SOURCES = t-changeexpiryjob.cpp $(support_src) t_wkdlookup_SOURCES = t-wkdlookup.cpp $(support_src) t_import_SOURCES = t-import.cpp $(support_src) +run_exportjob_SOURCES = run-exportjob.cpp run_importjob_SOURCES = run-importjob.cpp run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp @@ -75,7 +76,8 @@ BUILT_SOURCES = $(moc_files) pubring-stamp noinst_PROGRAMS = t-keylist t-keylocate t-ownertrust t-tofuinfo t-encrypt \ run-keyformailboxjob t-wkspublish t-verify t-various t-config t-remarks \ - t-trustsignatures t-changeexpiryjob t-wkdlookup t-import run-importjob + t-trustsignatures t-changeexpiryjob t-wkdlookup t-import run-importjob \ + run-exportjob CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ gpg-agent.conf pubring.kbx~ S.gpg-agent gpg.conf pubring.gpg~ \ diff --git a/lang/qt/tests/run-exportjob.cpp b/lang/qt/tests/run-exportjob.cpp new file mode 100644 index 00000000..1a1617da --- /dev/null +++ b/lang/qt/tests/run-exportjob.cpp @@ -0,0 +1,113 @@ +/* + run-exportjob.cpp + + This file is part of QGpgME's test suite. + Copyright (c) 2022 by g10 Code GmbH + Software engineering by Ingo Klöcker + + QGpgME is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + QGpgME is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. +*/ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#include + +#include + +#include + +using namespace GpgME; +using std::cout; +using std::cerr; + +static void showUsageAndExitWithCode(int exitCode) +{ + cerr << "Usage: run-exportjob [OPTION]... [PATTERN]...\n" + "Options:\n" + " --secret export secret keys instead of public keys\n" + + exit(exitCode); +} + +static auto createExportJob(unsigned int mode) +{ + if (mode & Context::ExportSecret) { + return QGpgME::openpgp()->secretKeyExportJob(/*armor=*/true); + } + return QGpgME::openpgp()->publicKeyExportJob(/*armor=*/true); +} + +int main(int argc, char *argv[]) +{ + GpgME::initializeLibrary(); + + QCoreApplication app{argc, argv}; + + unsigned int exportMode = 0; + + auto arguments = app.arguments(); + if (!arguments.isEmpty()) { + arguments.pop_front(); // remove program name + } + while (!arguments.isEmpty()) { + const auto &arg = arguments.front(); + if (!arg.startsWith(QLatin1String{"--"})) { + break; + } + if (arg == QLatin1String{"--"}) { + arguments.pop_front(); + break; + } + if (arg == QLatin1String{"--help"}) { + showUsageAndExitWithCode(0); + } else if (arg == QLatin1String{"--secret"}) { + exportMode = Context::ExportSecret; + arguments.pop_front(); + } else { + cerr << "Error: Invalid option " << arg.toStdString() << std::endl; + showUsageAndExitWithCode(1); + } + } + + auto job = createExportJob(exportMode); + QObject::connect(job, &QGpgME::ExportJob::result, + &app, [&app] (const GpgME::Error &err, const QByteArray &keyData, const QString &, const GpgME::Error &) { + if (err) { + cerr << "The ChangeExpiryJob failed with" << err.asString() << "."; + app.exit(1); + return; + } + cout << "Begin Result:\n" << keyData.toStdString() << "End Result:\n"; + app.exit(); + }); + job->start(arguments); + + return app.exec(); +}