From 77feaa451074741c2d07051915bc23d8b8377242 Mon Sep 17 00:00:00 2001 From: Andre Heinecke Date: Wed, 12 Feb 2020 11:52:24 +0100 Subject: [PATCH] qt: Add GpgCardJob following the job pattern * lang/qt/src/Makefile.am: Add new files. * lang/qt/src/job.cpp (GpgCardJob): Add impl stuff. * lang/qt/src/protocol.h (gpgCardJob): Get one. * lang/qt/src/qgpgmebackend.cpp, lang/qt/src/qgpgmebackend.h: Add helpers to get the job. * lang/qt/src/qgpgmegpgcardjob.cpp, lang/qt/src/gpgcardjob.h, lang/qt/src/qgpgmegpgcardjob.h: New. -- This is annoyingly complex to add a simple new job. In the future we should implement something like this without the threadedjobmixin stuff. But the idea was to follow the usual job pattern. GnuPG-Bug-Id: T4794 --- NEWS | 3 + lang/qt/src/Makefile.am | 10 ++- lang/qt/src/gpgcardjob.h | 92 ++++++++++++++++++++++ lang/qt/src/job.cpp | 3 + lang/qt/src/protocol.h | 8 ++ lang/qt/src/qgpgmebackend.cpp | 14 ++++ lang/qt/src/qgpgmebackend.h | 2 + lang/qt/src/qgpgmegpgcardjob.cpp | 129 +++++++++++++++++++++++++++++++ lang/qt/src/qgpgmegpgcardjob.h | 63 +++++++++++++++ 9 files changed, 322 insertions(+), 2 deletions(-) create mode 100644 lang/qt/src/gpgcardjob.h create mode 100644 lang/qt/src/qgpgmegpgcardjob.cpp create mode 100644 lang/qt/src/qgpgmegpgcardjob.h diff --git a/NEWS b/NEWS index dc9e0ff8..d87bc4ff 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ Noteworthy changes in version 1.14.0 (unreleased) * qt: Extended signkeyjob to handle remarks and multiple signatures. [#4734] + * qt: Added job API for gpg-card. + * Interface changes relative to the 1.13.1 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_user_id_t EXTENDED: New field 'uidhash'. @@ -19,6 +21,7 @@ Noteworthy changes in version 1.14.0 (unreleased) cpp: GpgSignKeyEditInteractor::setDupeOk NEW. qt: SignKeyJob::setDupeOk NEW. qt: SignKeyJob::setRemark NEW. + qt: GpgCardJob NEW. Noteworthy changes in version 1.13.1 (2019-06-13) diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 80dcde15..cbf6a530 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -38,6 +38,7 @@ qgpgme_sources = \ qgpgmekeyformailboxjob.cpp gpgme_backend_debug.cpp \ qgpgmetofupolicyjob.cpp qgpgmequickjob.cpp \ defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp \ + qgpgmegpgcardjob.cpp \ dn.cpp cryptoconfig.cpp # If you add one here make sure that you also add one in camelcase @@ -78,6 +79,7 @@ qgpgme_headers= \ defaultkeygenerationjob.h \ tofupolicyjob.h \ wkspublishjob.h \ + gpgcardjob.h \ dn.h camelcase_headers= \ @@ -116,7 +118,8 @@ camelcase_headers= \ KeyForMailboxJob \ DefaultKeyGenerationJob \ WKSPublishJob \ - TofuPolicyJob + TofuPolicyJob \ + GpgCardJob private_qgpgme_headers = \ qgpgme_export.h \ @@ -147,6 +150,7 @@ private_qgpgme_headers = \ qgpgmekeyformailboxjob.h \ qgpgmewkspublishjob.h \ qgpgmetofupolicyjob.h \ + qgpgmegpgcardjob.h \ qgpgmequickjob.h \ threadedjobmixin.h @@ -207,7 +211,9 @@ qgpgme_moc_sources = \ qgpgmekeyformailboxjob.moc \ defaultkeygenerationjob.moc \ quickjob.moc \ - qgpgmequickjob.moc + qgpgmequickjob.moc \ + gpgcardjob.moc \ + qgpgmegpgcardjob.moc qgpgmeincludedir = $(includedir)/qgpgme qgpgmeinclude_HEADERS = $(qgpgme_headers) diff --git a/lang/qt/src/gpgcardjob.h b/lang/qt/src/gpgcardjob.h new file mode 100644 index 00000000..63f5cf7c --- /dev/null +++ b/lang/qt/src/gpgcardjob.h @@ -0,0 +1,92 @@ +/* + gpgcardjob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2020 g10 Code GmbH + + QGpgME is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. +*/ +#ifndef __KLEO_GPGCARDJOB_H__ +#define __KLEO_GPGCARDJOB_H__ + +#include + +#include "job.h" + +namespace GpgME +{ +class Error; +} + +namespace QGpgME +{ + +/** + @short Get the best key to use for a Mailbox + + To use the keyformailboxjob, first obtain an instance from the + CryptoBackend and either exec it or start and + conncet the result() signals to a suitable slot. + The job will be automatically deleted in which + case the KeylistJob instance will have schedules it's own + destruction with a call to QObject::deleteLater(). + + The best key is defined as the key with a UID that has an + E-Mail that matches the mailbox provided. If multiple + keys are found the one with the highest validity is returned. + + After result() is emitted, the + KeyListJob will schedule it's own destruction by calling + QObject::deleteLater(). +*/ +class QGPGME_EXPORT GpgCardJob: public Job +{ + Q_OBJECT +protected: + explicit GpgCardJob(QObject *parent); + +public: + ~GpgCardJob(); + + /** + Starts the operation. \a cmds are the commands to + execute. + */ + virtual GpgME::Error start(const QStringList &cmds) = 0; + + virtual GpgME::Error exec(const QStringList &cmds, QString &std_out, QString &std_err, int &exitCode) = 0; + +Q_SIGNALS: + /** The resulting stdout and stderr of gpgcard and the exitCode + * + * The auditlog params are always null / empty. + */ + void result(const QString &std_out, const QString &std_err, int exitCode, + const QString &auditLogAsHtml = QString(), const GpgME::Error &auditLogError = GpgME::Error()); +}; + +} +#endif diff --git a/lang/qt/src/job.cpp b/lang/qt/src/job.cpp index c4270205..8ed0b576 100644 --- a/lang/qt/src/job.cpp +++ b/lang/qt/src/job.cpp @@ -65,6 +65,7 @@ #include "tofupolicyjob.h" #include "threadedjobmixin.h" #include "quickjob.h" +#include "gpgcardjob.h" #include #include @@ -141,6 +142,7 @@ make_job_subclass(KeyForMailboxJob) make_job_subclass(WKSPublishJob) make_job_subclass(TofuPolicyJob) make_job_subclass(QuickJob) +make_job_subclass(GpgCardJob) #undef make_job_subclass @@ -173,3 +175,4 @@ make_job_subclass(QuickJob) #include "wkspublishjob.moc" #include "tofupolicyjob.moc" #include "quickjob.moc" +#include "gpgcardjob.moc" diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index 1a52097e..17db68a5 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -67,6 +67,7 @@ class KeyForMailboxJob; class WKSPublishJob; class TofuPolicyJob; class QuickJob; +class GpgCardJob; /** The main entry point for QGpgME Comes in OpenPGP and SMIME(CMS) flavors. * @@ -184,5 +185,12 @@ QGPGME_EXPORT Protocol *smime(); */ QGPGME_EXPORT CryptoConfig *cryptoConfig(); +/** Obtain a reference to a protocol agnostic GpgCardJob. + * + * The reference is to a static object. + * @returns reference to a GpgCardJob following the job pattern. + */ +QGPGME_EXPORT GpgCardJob *gpgCardJob(); + } #endif diff --git a/lang/qt/src/qgpgmebackend.cpp b/lang/qt/src/qgpgmebackend.cpp index f7393f09..aa96db0d 100644 --- a/lang/qt/src/qgpgmebackend.cpp +++ b/lang/qt/src/qgpgmebackend.cpp @@ -38,6 +38,7 @@ #include "qgpgmebackend.h" +#include "qgpgmegpgcardjob.h" #include "error.h" #include "engineinfo.h" @@ -86,6 +87,11 @@ QGpgME::CryptoConfig *QGpgME::QGpgMEBackend::config() const return mCryptoConfig; } +QGpgME::GpgCardJob *QGpgME::QGpgMEBackend::gpgCardJob() const +{ + return new QGpgME::QGpgMEGpgCardJob(); +} + static bool check(GpgME::Protocol proto, QString *reason) { if (!GpgME::checkEngine(proto)) { @@ -206,3 +212,11 @@ QGpgME::Protocol *QGpgME::smime() } return gpgmeBackend->smime(); } + +QGpgME::GpgCardJob *QGpgME::gpgCardJob () +{ + if (!gpgmeBackend) { + gpgmeBackend = new QGpgME::QGpgMEBackend(); + } + return gpgmeBackend->gpgCardJob(); +} diff --git a/lang/qt/src/qgpgmebackend.h b/lang/qt/src/qgpgmebackend.h index a69b09a8..6c655e96 100644 --- a/lang/qt/src/qgpgmebackend.h +++ b/lang/qt/src/qgpgmebackend.h @@ -46,6 +46,7 @@ namespace QGpgME { class CryptoConfig; class Protocol; +class GpgCardJob; class QGpgMEBackend @@ -58,6 +59,7 @@ public: QString displayName() const; CryptoConfig *config() const; + GpgCardJob *gpgCardJob() const; Protocol *openpgp() const; Protocol *smime() const; diff --git a/lang/qt/src/qgpgmegpgcardjob.cpp b/lang/qt/src/qgpgmegpgcardjob.cpp new file mode 100644 index 00000000..a01ae604 --- /dev/null +++ b/lang/qt/src/qgpgmegpgcardjob.cpp @@ -0,0 +1,129 @@ +/* + qgpgmekeyformailboxjob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik + Software engineering by Intevation GmbH + + QGpgME is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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 "qgpgmegpgcardjob.h" + +#include +#include +#include +#include +#include "util.h" + +/* We cannot have a timeout because key generation can + * take ages. Well maybe 10 minutes. */ +#define TIMEOUT_VALUE (600000) + +#include + +using namespace GpgME; +using namespace QGpgME; + +QGpgMEGpgCardJob::QGpgMEGpgCardJob() + : mixin_type(nullptr) +{ + lateInitialization(); +} + +QGpgMEGpgCardJob::~QGpgMEGpgCardJob() {} + +static QString getGpgCardPath() +{ + auto bindir = QString::fromLocal8Bit(dirInfo("bindir")); + if (bindir.isEmpty()) { + return QString(); + } + + const QFileInfo fi(QDir(bindir).absoluteFilePath(QStringLiteral("gpg-card"))); + if (fi.exists() && fi.isExecutable()) { + return fi.absoluteFilePath(); + } + return QString(); +} + +static QGpgMEGpgCardJob::result_type do_work(const QStringList &cmds, const QString &path) +{ + QStringList args; + args << QStringLiteral("--with-colons"); + args += cmds; + + QProcess proc; + + proc.setProgram(path); + proc.setArguments(args); + proc.start(); + if (!proc.waitForStarted()) { + return std::make_tuple (QString(), QString(), 1, QString(), Error()); + } + + if (!proc.waitForFinished(TIMEOUT_VALUE)) { + return std::make_tuple (QString(), QString(), 1, QString(), Error()); + } + if (proc.exitStatus() == QProcess::NormalExit) { + return std::make_tuple (QString::fromUtf8(proc.readAllStandardOutput()), + QString::fromUtf8(proc.readAllStandardError()), proc.exitCode(), + QString(), Error()); + } + return std::make_tuple (QString::fromUtf8(proc.readAllStandardOutput()), + QString::fromUtf8(proc.readAllStandardError()), 1, + QString(), Error()); +} + +Error QGpgMEGpgCardJob::start(const QStringList &cmds) +{ + const auto cardpath = getGpgCardPath (); + if (cardpath.isEmpty()) { + return Error(make_error(GPG_ERR_NOT_SUPPORTED)); + } + run(std::bind(&do_work, cmds, cardpath)); + return Error(); +} + +Error QGpgMEGpgCardJob::exec(const QStringList &cmds, QString &std_out, QString &std_err, int &exitCode) +{ + const auto cardpath = getGpgCardPath (); + if (cardpath.isEmpty()) { + return Error(make_error(GPG_ERR_NOT_SUPPORTED)); + } + const result_type r = do_work(cmds, cardpath); + resultHook(r); + std_out = std::get<0>(r); + std_err = std::get<1>(r); + exitCode = std::get<2>(r); + return exitCode == 0 ? Error() : Error(make_error(GPG_ERR_GENERAL)); +} + +#include "qgpgmegpgcardjob.moc" diff --git a/lang/qt/src/qgpgmegpgcardjob.h b/lang/qt/src/qgpgmegpgcardjob.h new file mode 100644 index 00000000..bed68b2d --- /dev/null +++ b/lang/qt/src/qgpgmegpgcardjob.h @@ -0,0 +1,63 @@ +/* qgpgmegpgcardjob.h + + This file is part of libkleopatra, the KDE keymanagement library + Copyright (c) 2020 g10 Code GmbH + + QGpgME is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + 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. +*/ + +#ifndef __QGPGME_QGPGMEGPGCARDJOB_H__ +#define __QGPGME_QGPGMEGPGCARDJOB_H__ +#include "gpgcardjob.h" + +#include "threadedjobmixin.h" + +namespace QGpgME +{ + +class QGpgMEGpgCardJob +#ifdef Q_MOC_RUN + : public GpgCardJob +#else + : public _detail::ThreadedJobMixin > +#endif +{ + Q_OBJECT +#ifdef Q_MOC_RUN +public Q_SLOTS: + void slotFinished(); +#endif +public: + explicit QGpgMEGpgCardJob(); + ~QGpgMEGpgCardJob(); + + GpgME::Error start(const QStringList &cmds) Q_DECL_OVERRIDE; + + GpgME::Error exec(const QStringList &cmds, QString &std_out, QString &std_err, int &exitCode) Q_DECL_OVERRIDE; +}; + +} +#endif