From 275a3a2c16d27e5bc87f7d80af2ee703a92b6758 Mon Sep 17 00:00:00 2001 From: Ingo Klöcker Date: Fri, 27 Jan 2023 11:44:55 +0100 Subject: qt: Add data provider for list of file names * lang/qt/src/Makefile.am: Add new files and corresponding camel-case header. * lang/qt/src/dataprovider.h: Include interface from gpgme++ when not building. * lang/qt/src/filelistdataprovider.cpp, lang/qt/src/filelistdataprovider.h: New. -- The new data provider simplifies providing a nul-separated list of UTF-8-encoded filenames, e.g. for creating signed or encrypted archives. It is a simple read-only proxy for QByteArrayDataProvider. GnuPG-bug-id: 6342 --- lang/qt/src/Makefile.am | 3 ++ lang/qt/src/dataprovider.h | 6 +++ lang/qt/src/filelistdataprovider.cpp | 98 ++++++++++++++++++++++++++++++++++++ lang/qt/src/filelistdataprovider.h | 79 +++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 lang/qt/src/filelistdataprovider.cpp create mode 100644 lang/qt/src/filelistdataprovider.h (limited to 'lang/qt/src') diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 510802a8..40a73861 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -34,6 +34,7 @@ EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in \ qgpgme_sources = \ dataprovider.cpp \ debug.cpp \ + filelistdataprovider.cpp \ job.cpp multideletejob.cpp qgpgmeadduseridjob.cpp \ qgpgmeaddexistingsubkeyjob.cpp \ qgpgmebackend.cpp qgpgmechangeexpiryjob.cpp qgpgmechangeownertrustjob.cpp \ @@ -72,6 +73,7 @@ qgpgme_headers= \ downloadjob.h \ encryptjob.h \ exportjob.h \ + filelistdataprovider.h \ hierarchicalkeylistjob.h \ job.h \ keyformailboxjob.h \ @@ -120,6 +122,7 @@ camelcase_headers= \ DownloadJob \ EncryptJob \ ExportJob \ + FileListDataProvider \ HierarchicalKeyKistJob \ Job \ MultiDeleteJob \ diff --git a/lang/qt/src/dataprovider.h b/lang/qt/src/dataprovider.h index 636d6fb6..b14e7d54 100644 --- a/lang/qt/src/dataprovider.h +++ b/lang/qt/src/dataprovider.h @@ -25,7 +25,13 @@ #define __QGPGME_DATAPROVIDER_H__ #include "qgpgme_export.h" + +#ifdef BUILDING_QGPGME #include +#else +#include +#endif + #include #include diff --git a/lang/qt/src/filelistdataprovider.cpp b/lang/qt/src/filelistdataprovider.cpp new file mode 100644 index 00000000..004854ef --- /dev/null +++ b/lang/qt/src/filelistdataprovider.cpp @@ -0,0 +1,98 @@ +/* + filelistdataprovider.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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 "filelistdataprovider.h" + +#include "dataprovider.h" + +#include + +#include + +#include + +using namespace QGpgME; +using namespace GpgME; + +static QByteArray encodeFilenames(const std::vector &filenames) +{ + QByteArray ret; + if (filenames.empty()) { + return ret; + } + // calculate and reserve the needed minimum size of the result + const auto addSize = [](unsigned int n, const QString &s) { return n + s.size(); }; + const unsigned int minSize = filenames.size() + + std::accumulate(filenames.cbegin(), filenames.cend(), 0u, addSize); + ret.reserve(minSize); + // pack the filenames into the byte array + for (const auto &f : filenames) { + if (!f.isEmpty()) { + ret += f.toUtf8() + '\0'; + } + } + ret.chop(1); // remove the trailing nul + return ret; +} + +FileListDataProvider::FileListDataProvider(const std::vector &filenames) + : mProvider{new QByteArrayDataProvider{encodeFilenames(filenames)}} +{ +} + +FileListDataProvider::~FileListDataProvider() = default; + +ssize_t FileListDataProvider::read(void* buffer, size_t bufSize) +{ + return mProvider->read(buffer, bufSize); +} + +ssize_t FileListDataProvider::write(const void *, size_t) +{ + Error::setSystemError(GPG_ERR_EBADF); + return -1; +} + +off_t FileListDataProvider::seek(off_t offset, int whence) +{ + return mProvider->seek(offset, whence); +} + +void FileListDataProvider::release() +{ + mProvider->release(); +} diff --git a/lang/qt/src/filelistdataprovider.h b/lang/qt/src/filelistdataprovider.h new file mode 100644 index 00000000..25e52e41 --- /dev/null +++ b/lang/qt/src/filelistdataprovider.h @@ -0,0 +1,79 @@ +/* + filelistdataprovider.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_FILELISTDATAPROVIDER_H__ +#define __QGPGME_FILELISTDATAPROVIDER_H__ + +#include "qgpgme_export.h" + +#ifdef BUILDING_QGPGME +#include +#else +#include +#endif + +#include +#include + +class QString; + +namespace QGpgME +{ + +/** + * This read-only data provider simplifies providing a nul-separated list of + * UTF-8-encoded filenames, e.g. for creating signed or encrypted archives. + */ +class QGPGME_EXPORT FileListDataProvider : public GpgME::DataProvider +{ +public: + explicit FileListDataProvider(const std::vector &filenames); + ~FileListDataProvider() override; + +private: + bool isSupported(Operation op) const override + { + return op != Operation::Write; + } + ssize_t read(void *buffer, size_t bufSize) override; + ssize_t write(const void *buffer, size_t bufSize) override; + off_t seek(off_t offset, int whence) override; + void release() override; + +private: + std::unique_ptr mProvider; +}; + +} + +#endif // __QGPGME_FILELISTDATAPROVIDER_H__ -- cgit From 7afd135ccec73585e06272f98b4a0895e3ee6579 Mon Sep 17 00:00:00 2001 From: Ingo Klöcker Date: Fri, 27 Jan 2023 11:53:45 +0100 Subject: qt: Add job for creating encrypted archives * lang/qt/src/encryptarchivejob.cpp, lang/qt/src/encryptarchivejob.h, lang/qt/src/encryptarchivejob_p.h, lang/qt/src/qgpgmeencryptarchivejob.cpp, lang/qt/src/qgpgmeencryptarchivejob.h: New. * lang/qt/src/protocol.h (class Protocol): Add pure virtual member function encryptArchiveJob * lang/qt/src/protocol_p.h (Protocol::encryptArchiveJob): ... and implement it. * lang/qt/src/Makefile.am: Update accordingly. * lang/qt/tests/run-encryptarchivejob.cpp: New. * lang/qt/tests/Makefile.am: Add new test runner. -- GnuPG-bug-id: 6342 --- NEWS | 4 + lang/qt/src/Makefile.am | 8 ++ lang/qt/src/encryptarchivejob.cpp | 62 +++++++++++++ lang/qt/src/encryptarchivejob.h | 101 ++++++++++++++++++++ lang/qt/src/encryptarchivejob_p.h | 49 ++++++++++ lang/qt/src/protocol.h | 3 + lang/qt/src/protocol_p.h | 13 +++ lang/qt/src/qgpgmeencryptarchivejob.cpp | 152 ++++++++++++++++++++++++++++++ lang/qt/src/qgpgmeencryptarchivejob.h | 82 +++++++++++++++++ lang/qt/tests/Makefile.am | 2 + lang/qt/tests/run-encryptarchivejob.cpp | 158 ++++++++++++++++++++++++++++++++ 11 files changed, 634 insertions(+) create mode 100644 lang/qt/src/encryptarchivejob.cpp create mode 100644 lang/qt/src/encryptarchivejob.h create mode 100644 lang/qt/src/encryptarchivejob_p.h create mode 100644 lang/qt/src/qgpgmeencryptarchivejob.cpp create mode 100644 lang/qt/src/qgpgmeencryptarchivejob.h create mode 100644 lang/qt/tests/run-encryptarchivejob.cpp (limited to 'lang/qt/src') diff --git a/NEWS b/NEWS index a96973cd..f36be620 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,8 @@ Noteworthy changes in version 1.18.1 (unreleased) * qt: Allow deferred start of import jobs. [T6323] + * qt: Support creating encrypted archives. [T6342] + * Interface changes relative to the 1.18.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ gpgme_get_ctx_flag EXTENDED: New flag 'no-auto-check-trustdb'. @@ -50,6 +52,8 @@ Noteworthy changes in version 1.18.1 (unreleased) qt: Job::startNow NEW. qt: ImportJob::startLater NEW. qt: FileListDataProvider NEW. + qt: EncryptArchiveJob NEW. + qt: Protocol::encryptArchiveJob NEW. Noteworthy changes in version 1.18.0 (2022-08-10) diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 40a73861..240e5716 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -34,12 +34,14 @@ EXTRA_DIST = QGpgmeConfig.cmake.in.in QGpgmeConfigVersion.cmake.in \ qgpgme_sources = \ dataprovider.cpp \ debug.cpp \ + encryptarchivejob.cpp \ filelistdataprovider.cpp \ job.cpp multideletejob.cpp qgpgmeadduseridjob.cpp \ qgpgmeaddexistingsubkeyjob.cpp \ qgpgmebackend.cpp qgpgmechangeexpiryjob.cpp qgpgmechangeownertrustjob.cpp \ qgpgmechangepasswdjob.cpp qgpgmedecryptjob.cpp \ qgpgmedecryptverifyjob.cpp qgpgmedeletejob.cpp qgpgmedownloadjob.cpp \ + qgpgmeencryptarchivejob.cpp \ qgpgmeencryptjob.cpp qgpgmeexportjob.cpp qgpgmeimportfromkeyserverjob.cpp \ qgpgmeimportjob.cpp qgpgmekeygenerationjob.cpp qgpgmekeylistjob.cpp \ listallkeysjob.cpp qgpgmelistallkeysjob.cpp qgpgmenewcryptoconfig.cpp \ @@ -71,6 +73,7 @@ qgpgme_headers= \ decryptjob.h \ decryptverifyjob.h \ downloadjob.h \ + encryptarchivejob.h \ encryptjob.h \ exportjob.h \ filelistdataprovider.h \ @@ -120,6 +123,7 @@ camelcase_headers= \ DecryptVerifyJob \ DN \ DownloadJob \ + EncryptArchiveJob \ EncryptJob \ ExportJob \ FileListDataProvider \ @@ -156,6 +160,7 @@ camelcase_headers= \ private_qgpgme_headers = \ changeexpiryjob_p.h \ + encryptarchivejob_p.h \ encryptjob_p.h \ importjob_p.h \ listallkeysjob_p.h \ @@ -172,6 +177,7 @@ private_qgpgme_headers = \ qgpgmedecryptverifyjob.h \ qgpgmedeletejob.h \ qgpgmedownloadjob.h \ + qgpgmeencryptarchivejob.h \ qgpgmeencryptjob.h \ qgpgmeexportjob.h \ qgpgmeimportfromkeyserverjob.h \ @@ -209,6 +215,7 @@ qgpgme_moc_sources = \ decryptverifyjob.moc \ deletejob.moc \ downloadjob.moc \ + encryptarchivejob.moc \ encryptjob.moc \ exportjob.moc \ hierarchicalkeylistjob.moc \ @@ -228,6 +235,7 @@ qgpgme_moc_sources = \ qgpgmedecryptverifyjob.moc \ qgpgmedeletejob.moc \ qgpgmedownloadjob.moc \ + qgpgmeencryptarchivejob.moc \ qgpgmeencryptjob.moc \ qgpgmeexportjob.moc \ qgpgmeimportfromkeyserverjob.moc \ diff --git a/lang/qt/src/encryptarchivejob.cpp b/lang/qt/src/encryptarchivejob.cpp new file mode 100644 index 00000000..5c5533be --- /dev/null +++ b/lang/qt/src/encryptarchivejob.cpp @@ -0,0 +1,62 @@ +/* + encryptarchivejob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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 "encryptarchivejob.h" +#include "encryptarchivejob_p.h" + +using namespace QGpgME; + +EncryptArchiveJob::EncryptArchiveJob(QObject *parent) + : Job{parent} +{ +} + +EncryptArchiveJob::~EncryptArchiveJob() = default; + +void EncryptArchiveJob::setBaseDirectory(const QString &baseDirectory) +{ + auto d = jobPrivate(this); + d->m_baseDirectory = baseDirectory; +} + +QString EncryptArchiveJob::baseDirectory() const +{ + auto d = jobPrivate(this); + return d->m_baseDirectory; +} + +#include "encryptarchivejob.moc" diff --git a/lang/qt/src/encryptarchivejob.h b/lang/qt/src/encryptarchivejob.h new file mode 100644 index 00000000..1221994f --- /dev/null +++ b/lang/qt/src/encryptarchivejob.h @@ -0,0 +1,101 @@ +/* + encryptarchivejob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_ENCRYPTARCHIVEJOB_H__ +#define __QGPGME_ENCRYPTARCHIVEJOB_H__ + +#include "job.h" + +#ifdef BUILDING_QGPGME +# include "context.h" +#else +# include +#endif + +namespace GpgME +{ +class Key; +} + +namespace QGpgME +{ + +/** + * Abstract base class for job for creating encrypted archives + */ +class QGPGME_EXPORT EncryptArchiveJob : public Job +{ + Q_OBJECT +protected: + explicit EncryptArchiveJob(QObject *parent); +public: + ~EncryptArchiveJob() override; + + void setBaseDirectory(const QString &baseDirectory); + QString baseDirectory() const; + + /** + * Starts the creation of an encrypted archive. + * + * Encrypts the files and directories in \a paths into an archive for the + * keys in \a recipients. If \a recipients is empty, then symmetric + * encryption is performed. The encrypted archive is written to \a cipherText. + * + * Emits result() when the job has finished. + */ + virtual GpgME::Error start(const std::vector &recipients, + const std::vector &paths, + const std::shared_ptr &cipherText, + const GpgME::Context::EncryptionFlags flags) = 0; + + /** + * Creates an encrypted archive. + * + * Encrypts the files and directories in \a paths into an archive for the + * keys in \a recipients. If \a recipients is empty, then symmetric + * encryption is performed. The encrypted archive is written to \a cipherText. + */ + // virtual GpgME::EncryptionResult exec(const std::vector &recipients, + // const std::vector &paths, + // const std::shared_ptr &cipherText, + // const GpgME::Context::EncryptionFlags flags) = 0; + +Q_SIGNALS: + void result(const GpgME::EncryptionResult &result, + const QString &auditLogAsHtml = {}, + const GpgME::Error &auditLogError = {}); +}; + +} + +#endif // __QGPGME_ENCRYPTARCHIVEJOB_H__ diff --git a/lang/qt/src/encryptarchivejob_p.h b/lang/qt/src/encryptarchivejob_p.h new file mode 100644 index 00000000..798096db --- /dev/null +++ b/lang/qt/src/encryptarchivejob_p.h @@ -0,0 +1,49 @@ +/* + encryptarchivejob_p.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_ENCRYPTARCHIVEJOB_P_H__ +#define __QGPGME_ENCRYPTARCHIVEJOB_P_H__ + +#include "job_p.h" + +namespace QGpgME +{ + +struct EncryptArchiveJobPrivate : public JobPrivate +{ + QString m_baseDirectory; +}; + +} + +#endif // __QGPGME_ENCRYPTARCHIVEJOB_P_H__ diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index 019633a8..bb9f060b 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -50,6 +50,7 @@ class ImportFromKeyserverJob; class ExportJob; class DownloadJob; class DeleteJob; +class EncryptArchiveJob; class EncryptJob; class DecryptJob; class SignJob; @@ -189,6 +190,8 @@ public: * OpenPGP key. */ virtual SetPrimaryUserIDJob *setPrimaryUserIDJob() const = 0; + + virtual EncryptArchiveJob *encryptArchiveJob(bool armor = false) const = 0; }; /** Obtain a reference to the OpenPGP Protocol. diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h index 915fef99..e6b2b8a8 100644 --- a/lang/qt/src/protocol_p.h +++ b/lang/qt/src/protocol_p.h @@ -46,6 +46,7 @@ #include "qgpgmedeletejob.h" #include "qgpgmedownloadjob.h" #include "qgpgmesignencryptjob.h" +#include "qgpgmeencryptarchivejob.h" #include "qgpgmeencryptjob.h" #include "qgpgmesignjob.h" #include "qgpgmesignkeyjob.h" @@ -506,6 +507,18 @@ public: } return new QGpgME::QGpgMESetPrimaryUserIDJob{context}; } + + QGpgME::EncryptArchiveJob *encryptArchiveJob(bool armor) const override + { + if (mProtocol != GpgME::OpenPGP) { + return nullptr; + } + if (auto context = GpgME::Context::createForProtocol(mProtocol)) { + context->setArmor(armor); + return new QGpgME::QGpgMEEncryptArchiveJob{context}; + } + return nullptr; + } }; } diff --git a/lang/qt/src/qgpgmeencryptarchivejob.cpp b/lang/qt/src/qgpgmeencryptarchivejob.cpp new file mode 100644 index 00000000..63c55364 --- /dev/null +++ b/lang/qt/src/qgpgmeencryptarchivejob.cpp @@ -0,0 +1,152 @@ +/* + qgpgmeencryptarchivejob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB + Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik + Software engineering by Intevation GmbH + Copyright (c) 2022,2023 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 + 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 "qgpgmeencryptarchivejob.h" + +#include "dataprovider.h" +#include "encryptarchivejob_p.h" +#include "filelistdataprovider.h" + +// #include +#include +// #include +// +// #include +// #include +// +// #include + +using namespace QGpgME; +using namespace GpgME; + +namespace +{ + +class QGpgMEEncryptArchiveJobPrivate : public EncryptArchiveJobPrivate +{ + QGpgMEEncryptArchiveJob *q = nullptr; + +public: + QGpgMEEncryptArchiveJobPrivate(QGpgMEEncryptArchiveJob *qq) + : q{qq} + { + } + + ~QGpgMEEncryptArchiveJobPrivate() override = default; + +private: + void start() override + { + q->run(); + } +}; + +} + +QGpgMEEncryptArchiveJob::QGpgMEEncryptArchiveJob(Context *context) + : mixin_type{context} +{ + setJobPrivate(this, std::unique_ptr{new QGpgMEEncryptArchiveJobPrivate{this}}); + lateInitialization(); +} + +static QGpgMEEncryptArchiveJob::result_type encrypt(Context *ctx, + QThread *thread, + const std::vector &recipients, + const std::vector &paths, + const std::weak_ptr &cipherText_, + Context::EncryptionFlags flags, + const QString &baseDirectory) +{ + const std::shared_ptr cipherText = cipherText_.lock(); + const _detail::ToThreadMover ctMover(cipherText, thread); + + QGpgME::FileListDataProvider in{paths}; + Data indata(&in); + if (!baseDirectory.isEmpty()) { + indata.setFileName(baseDirectory.toStdString()); + } + + QGpgME::QIODeviceDataProvider out{cipherText}; + Data outdata(&out); + + flags = static_cast(flags | Context::EncryptArchive); + const EncryptionResult res = ctx->encrypt(recipients, indata, outdata, flags); + Error ae; + const QString log = _detail::audit_log_as_html(ctx, ae); + return std::make_tuple(res, log, ae); +} + +GpgME::Error QGpgMEEncryptArchiveJob::start(const std::vector &recipients, + const std::vector &paths, + const std::shared_ptr &cipherText, + const GpgME::Context::EncryptionFlags flags) +{ + if (!cipherText) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + run(std::bind(&encrypt, + std::placeholders::_1, + std::placeholders::_2, + recipients, + paths, + std::placeholders::_3, + flags, + baseDirectory()), + cipherText); + return {}; +} + +// EncryptionResult QGpgMEEncryptArchiveJob::exec(const std::vector &recipients, const QByteArray &plainText, +// const Context::EncryptionFlags eflags, QByteArray &cipherText) +// { +// const result_type r = encrypt_qba(context(), recipients, plainText, eflags, mOutputIsBase64Encoded, fileName()); +// cipherText = std::get<1>(r); +// resultHook(r); +// return mResult; +// } + +void QGpgMEEncryptArchiveJob::resultHook(const result_type &tuple) +{ + mResult = std::get<0>(tuple); +} + +#include "qgpgmeencryptarchivejob.moc" diff --git a/lang/qt/src/qgpgmeencryptarchivejob.h b/lang/qt/src/qgpgmeencryptarchivejob.h new file mode 100644 index 00000000..81398d07 --- /dev/null +++ b/lang/qt/src/qgpgmeencryptarchivejob.h @@ -0,0 +1,82 @@ +/* + qgpgmeencryptarchivejob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_QGPGMEENCRYPTARCHIVEJOB_H__ +#define __QGPGME_QGPGMEENCRYPTARCHIVEJOB_H__ + +#include "encryptarchivejob.h" + +#include "threadedjobmixin.h" + +#include +#include + +namespace QGpgME +{ + +class QGpgMEEncryptArchiveJob +#ifdef Q_MOC_RUN + : public EncryptArchiveJob +#else + : public _detail::ThreadedJobMixin> +#endif +{ + Q_OBJECT +#ifdef Q_MOC_RUN +public Q_SLOTS: + void slotFinished(); +#endif +public: + explicit QGpgMEEncryptArchiveJob(GpgME::Context *context); + ~QGpgMEEncryptArchiveJob() = default; + + GpgME::Error start(const std::vector &recipients, + const std::vector &paths, + const std::shared_ptr &cipherText, + const GpgME::Context::EncryptionFlags flags) override; + + // GpgME::EncryptionResult exec(const std::vector &recipients, + // const std::vector &paths, + // const std::shared_ptr &cipherText, + // const GpgME::Context::EncryptionFlags flags) override; + + /* from ThreadedJobMixin */ + void resultHook(const result_type &r) override; + +private: + GpgME::EncryptionResult mResult; +}; + +} + +#endif // __QGPGME_QGPGMEENCRYPTARCHIVEJOB_H__ diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am index 564a9ff7..97e2b417 100644 --- a/lang/qt/tests/Makefile.am +++ b/lang/qt/tests/Makefile.am @@ -86,6 +86,7 @@ t_wkdlookup_SOURCES = t-wkdlookup.cpp $(support_src) t_import_SOURCES = t-import.cpp $(support_src) t_revokekey_SOURCES = t-revokekey.cpp $(support_src) t_setprimaryuserid_SOURCES = t-setprimaryuserid.cpp $(support_src) +run_encryptarchivejob_SOURCES = run-encryptarchivejob.cpp run_exportjob_SOURCES = run-exportjob.cpp run_importjob_SOURCES = run-importjob.cpp run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp @@ -102,6 +103,7 @@ noinst_PROGRAMS = \ run-keyformailboxjob t-wkspublish t-verify t-various t-config t-remarks \ t-trustsignatures t-changeexpiryjob t-wkdlookup t-import t-revokekey \ t-setprimaryuserid \ + run-encryptarchivejob \ run-importjob run-exportjob run-receivekeysjob run-refreshkeysjob CLEANFILES = secring.gpg pubring.gpg pubring.kbx trustdb.gpg dirmngr.conf \ diff --git a/lang/qt/tests/run-encryptarchivejob.cpp b/lang/qt/tests/run-encryptarchivejob.cpp new file mode 100644 index 00000000..e48af9f8 --- /dev/null +++ b/lang/qt/tests/run-encryptarchivejob.cpp @@ -0,0 +1,158 @@ +/* + run-encryptarchivejob.cpp + + This file is part of QGpgME's test suite. + Copyright (c) 2023 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 +#include + +#include +#include + +#include +#include + +using namespace GpgME; + +std::ostream &operator<<(std::ostream &os, const QString &s) +{ + return os << s.toLocal8Bit().constData(); +} + +const char *displayName(Protocol protocol) +{ + switch (protocol) { + case GpgME::OpenPGP: + return "OpenPGP"; + case GpgME::CMS: + return "S/MIME"; + default: + return "Unknown protocol"; + } +} + +struct CommandLineOptions { + bool armor; + QString archiveName; + QString baseDirectory; + std::vector filesAndDirectories; +}; + +CommandLineOptions parseCommandLine(const QStringList &arguments) +{ + CommandLineOptions options; + + QCommandLineParser parser; + parser.setApplicationDescription("Test program for EncryptArchiveJob"); + parser.addHelpOption(); + parser.addOptions({ + {{"o", "output"}, "Write output to FILE.", "FILE"}, + {{"a", "armor"}, "Create ASCII armored output."}, + {{"C", "directory"}, "Change to DIRECTORY before creating the archive.", "DIRECTORY"}, + }); + parser.addPositionalArgument("files", "Files and directories to add to the archive", "[files] [directories]"); + + parser.process(arguments); + + const auto args = parser.positionalArguments(); + if (args.empty()) { + parser.showHelp(1); + } + + options.armor = parser.isSet("armor"); + options.archiveName = parser.value("output"); + options.baseDirectory = parser.value("directory"); + std::copy(args.begin(), args.end(), std::back_inserter(options.filesAndDirectories)); + + return options; +} + +std::shared_ptr createOutput(const QString &fileName) +{ + std::shared_ptr output; + + if (fileName.isEmpty()) { + output.reset(new QFile); + output->open(stdout, QIODevice::WriteOnly); + } else { + if (QFile::exists(fileName)) { + qCritical() << "File" << fileName << "exists. Bailing out."; + } else { + output.reset(new QFile{fileName}); + output->open(QIODevice::WriteOnly); + } + } + + return output; +} + +int main(int argc, char **argv) +{ + GpgME::initializeLibrary(); + + QCoreApplication app{argc, argv}; + app.setApplicationName("run-encryptarchivejob"); + + const auto options = parseCommandLine(app.arguments()); + + auto output = createOutput(options.archiveName); + if (!output) { + return 1; + } + + auto job = QGpgME::openpgp()->encryptArchiveJob(options.armor); + if (!job) { + std::cerr << "Error: Could not create job" << std::endl; + return 1; + } + job->setBaseDirectory(options.baseDirectory); + QObject::connect(job, &QGpgME::EncryptArchiveJob::result, &app, [](const GpgME::EncryptionResult &result, const QString &auditLog, const GpgME::Error &) { + std::cerr << "Diagnostics: " << auditLog << std::endl; + std::cerr << "Result: " << result << std::endl; + qApp->quit(); + }); + + const auto err = job->start({}, options.filesAndDirectories, output, GpgME::Context::None); + if (err) { + std::cerr << "Error: Starting the job failed: " << err.asString() << std::endl; + return 1; + } + + return app.exec(); +} -- cgit From 8d672b3b7e5c5d487f20fb742a29fbee21236885 Mon Sep 17 00:00:00 2001 From: Ingo Klöcker Date: Mon, 30 Jan 2023 12:56:54 +0100 Subject: qt: Add job for creating signed archives * lang/qt/src/signarchivejob.cpp, lang/qt/src/signarchivejob.h, lang/qt/src/signarchivejob_p.h, lang/qt/src/qgpgmesignarchivejob.cpp, lang/qt/src/qgpgmesignarchivejob.h: New. * lang/qt/src/protocol.h (class Protocol): Add pure virtual member function signArchiveJob * lang/qt/src/protocol_p.h (Protocol::signArchiveJob): ... and implement it. * lang/qt/src/Makefile.am: Update accordingly. * lang/qt/tests/run-signarchivejob.cpp: New. * lang/qt/tests/Makefile.am: Add new test runner. -- GnuPG-bug-id: 6342 --- lang/qt/src/Makefile.am | 8 ++ lang/qt/src/protocol.h | 2 + lang/qt/src/protocol_p.h | 13 ++++ lang/qt/src/qgpgmesignarchivejob.cpp | 141 ++++++++++++++++++++++++++++++++++ lang/qt/src/qgpgmesignarchivejob.h | 76 ++++++++++++++++++ lang/qt/src/signarchivejob.cpp | 62 +++++++++++++++ lang/qt/src/signarchivejob.h | 88 +++++++++++++++++++++ lang/qt/src/signarchivejob_p.h | 49 ++++++++++++ lang/qt/tests/Makefile.am | 5 +- lang/qt/tests/run-signarchivejob.cpp | 145 +++++++++++++++++++++++++++++++++++ 10 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 lang/qt/src/qgpgmesignarchivejob.cpp create mode 100644 lang/qt/src/qgpgmesignarchivejob.h create mode 100644 lang/qt/src/signarchivejob.cpp create mode 100644 lang/qt/src/signarchivejob.h create mode 100644 lang/qt/src/signarchivejob_p.h create mode 100644 lang/qt/tests/run-signarchivejob.cpp (limited to 'lang/qt/src') diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am index 240e5716..928b6913 100644 --- a/lang/qt/src/Makefile.am +++ b/lang/qt/src/Makefile.am @@ -49,6 +49,7 @@ qgpgme_sources = \ qgpgmerefreshsmimekeysjob.cpp \ qgpgmerevokekeyjob.cpp \ qgpgmesetprimaryuseridjob.cpp \ + qgpgmesignarchivejob.cpp \ qgpgmesignencryptjob.cpp \ qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \ qgpgmeverifyopaquejob.cpp qgpgmewkdlookupjob.cpp threadedjobmixin.cpp \ @@ -56,6 +57,7 @@ qgpgme_sources = \ qgpgmetofupolicyjob.cpp qgpgmequickjob.cpp \ defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp \ qgpgmegpgcardjob.cpp changeexpiryjob.cpp encryptjob.cpp importjob.cpp \ + signarchivejob.cpp \ signencryptjob.cpp \ dn.cpp cryptoconfig.cpp wkdlookupresult.cpp \ util.cpp @@ -89,6 +91,7 @@ qgpgme_headers= \ revokekeyjob.h \ setprimaryuseridjob.h \ specialjob.h \ + signarchivejob.h \ signjob.h \ signkeyjob.h \ signencryptjob.h \ @@ -137,6 +140,7 @@ camelcase_headers= \ RevokeKeyJob \ SetPrimaryUserIDJob \ SpecialJob \ + SignArchiveJob \ SignJob \ SignKeyJob \ SignEncryptJob \ @@ -189,6 +193,7 @@ private_qgpgme_headers = \ qgpgmerefreshsmimekeysjob.h \ qgpgmerevokekeyjob.h \ qgpgmesetprimaryuseridjob.h \ + qgpgmesignarchivejob.h \ qgpgmesignencryptjob.h \ qgpgmesignjob.h \ qgpgmesignkeyjob.h \ @@ -200,6 +205,7 @@ private_qgpgme_headers = \ qgpgmetofupolicyjob.h \ qgpgmegpgcardjob.h \ qgpgmequickjob.h \ + signarchivejob_p.h \ signencryptjob_p.h \ threadedjobmixin.h \ util.h @@ -247,6 +253,7 @@ qgpgme_moc_sources = \ qgpgmerefreshsmimekeysjob.moc \ qgpgmerevokekeyjob.moc \ qgpgmesetprimaryuseridjob.moc \ + qgpgmesignarchivejob.moc \ qgpgmesignencryptjob.moc \ qgpgmesignjob.moc \ qgpgmesignkeyjob.moc \ @@ -260,6 +267,7 @@ qgpgme_moc_sources = \ refreshkeysjob.moc \ revokekeyjob.moc \ setprimaryuseridjob.moc \ + signarchivejob.moc \ signencryptjob.moc \ signjob.moc \ signkeyjob.moc \ diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h index bb9f060b..0f3e5b28 100644 --- a/lang/qt/src/protocol.h +++ b/lang/qt/src/protocol.h @@ -53,6 +53,7 @@ class DeleteJob; class EncryptArchiveJob; class EncryptJob; class DecryptJob; +class SignArchiveJob; class SignJob; class SignKeyJob; class VerifyDetachedJob; @@ -192,6 +193,7 @@ public: virtual SetPrimaryUserIDJob *setPrimaryUserIDJob() const = 0; virtual EncryptArchiveJob *encryptArchiveJob(bool armor = false) const = 0; + virtual SignArchiveJob *signArchiveJob(bool armor = false) const = 0; }; /** Obtain a reference to the OpenPGP Protocol. diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h index e6b2b8a8..73405c6d 100644 --- a/lang/qt/src/protocol_p.h +++ b/lang/qt/src/protocol_p.h @@ -48,6 +48,7 @@ #include "qgpgmesignencryptjob.h" #include "qgpgmeencryptarchivejob.h" #include "qgpgmeencryptjob.h" +#include "qgpgmesignarchivejob.h" #include "qgpgmesignjob.h" #include "qgpgmesignkeyjob.h" #include "qgpgmeexportjob.h" @@ -519,6 +520,18 @@ public: } return nullptr; } + + QGpgME::SignArchiveJob *signArchiveJob(bool armor) const override + { + if (mProtocol != GpgME::OpenPGP) { + return nullptr; + } + if (auto context = GpgME::Context::createForProtocol(mProtocol)) { + context->setArmor(armor); + return new QGpgME::QGpgMESignArchiveJob{context}; + } + return nullptr; + } }; } diff --git a/lang/qt/src/qgpgmesignarchivejob.cpp b/lang/qt/src/qgpgmesignarchivejob.cpp new file mode 100644 index 00000000..d9abec42 --- /dev/null +++ b/lang/qt/src/qgpgmesignarchivejob.cpp @@ -0,0 +1,141 @@ +/* + qgpgmesignarchivejob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2004,2007,2008 Klarälvdalens Datakonsult AB + Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik + Software engineering by Intevation GmbH + Copyright (c) 2022,2023 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 + 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 "qgpgmesignarchivejob.h" + +#include "dataprovider.h" +#include "signarchivejob_p.h" +#include "filelistdataprovider.h" + +#include + +using namespace QGpgME; +using namespace GpgME; + +namespace +{ + +class QGpgMESignArchiveJobPrivate : public SignArchiveJobPrivate +{ + QGpgMESignArchiveJob *q = nullptr; + +public: + QGpgMESignArchiveJobPrivate(QGpgMESignArchiveJob *qq) + : q{qq} + { + } + + ~QGpgMESignArchiveJobPrivate() override = default; + +private: + void start() override + { + q->run(); + } +}; + +} + +QGpgMESignArchiveJob::QGpgMESignArchiveJob(Context *context) + : mixin_type{context} +{ + setJobPrivate(this, std::unique_ptr{new QGpgMESignArchiveJobPrivate{this}}); + lateInitialization(); +} + +static QGpgMESignArchiveJob::result_type sign(Context *ctx, + QThread *thread, + const std::vector &signers, + const std::vector &paths, + const std::weak_ptr &output_, + const QString &baseDirectory) +{ + const std::shared_ptr output = output_.lock(); + const _detail::ToThreadMover ctMover(output, thread); + + QGpgME::FileListDataProvider in{paths}; + Data indata(&in); + if (!baseDirectory.isEmpty()) { + indata.setFileName(baseDirectory.toStdString()); + } + + QGpgME::QIODeviceDataProvider out{output}; + Data outdata(&out); + + ctx->clearSigningKeys(); + for (const Key &signer : signers) { + if (!signer.isNull()) { + if (const Error err = ctx->addSigningKey(signer)) { + return std::make_tuple(SigningResult{err}, QString{}, Error{}); + } + } + } + + const SigningResult res = ctx->sign(indata, outdata, GpgME::SignArchive); + Error ae; + const QString log = _detail::audit_log_as_html(ctx, ae); + return std::make_tuple(res, log, ae); +} + +GpgME::Error QGpgMESignArchiveJob::start(const std::vector &signers, + const std::vector &paths, + const std::shared_ptr &output) +{ + if (!output) { + return Error::fromCode(GPG_ERR_INV_VALUE); + } + + run(std::bind(&sign, + std::placeholders::_1, + std::placeholders::_2, + signers, + paths, + std::placeholders::_3, + baseDirectory()), + output); + return {}; +} + +void QGpgMESignArchiveJob::resultHook(const result_type &tuple) +{ + mResult = std::get<0>(tuple); +} + +#include "qgpgmesignarchivejob.moc" diff --git a/lang/qt/src/qgpgmesignarchivejob.h b/lang/qt/src/qgpgmesignarchivejob.h new file mode 100644 index 00000000..ade4e8dc --- /dev/null +++ b/lang/qt/src/qgpgmesignarchivejob.h @@ -0,0 +1,76 @@ +/* + qgpgmesignarchivejob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_QGPGMESIGNARCHIVEJOB_H__ +#define __QGPGME_QGPGMESIGNARCHIVEJOB_H__ + +#include "signarchivejob.h" + +#include "threadedjobmixin.h" + +#include +#include + +namespace QGpgME +{ + +class QGpgMESignArchiveJob +#ifdef Q_MOC_RUN + : public SignArchiveJob +#else + : public _detail::ThreadedJobMixin> +#endif +{ + Q_OBJECT +#ifdef Q_MOC_RUN +public Q_SLOTS: + void slotFinished(); +#endif +public: + explicit QGpgMESignArchiveJob(GpgME::Context *context); + ~QGpgMESignArchiveJob() = default; + + GpgME::Error start(const std::vector &signers, + const std::vector &paths, + const std::shared_ptr &output) override; + + /* from ThreadedJobMixin */ + void resultHook(const result_type &r) override; + +private: + GpgME::SigningResult mResult; +}; + +} + +#endif // __QGPGME_QGPGMESIGNARCHIVEJOB_H__ diff --git a/lang/qt/src/signarchivejob.cpp b/lang/qt/src/signarchivejob.cpp new file mode 100644 index 00000000..fcdf241d --- /dev/null +++ b/lang/qt/src/signarchivejob.cpp @@ -0,0 +1,62 @@ +/* + signarchivejob.cpp + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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 "signarchivejob.h" +#include "signarchivejob_p.h" + +using namespace QGpgME; + +SignArchiveJob::SignArchiveJob(QObject *parent) + : Job{parent} +{ +} + +SignArchiveJob::~SignArchiveJob() = default; + +void SignArchiveJob::setBaseDirectory(const QString &baseDirectory) +{ + auto d = jobPrivate(this); + d->m_baseDirectory = baseDirectory; +} + +QString SignArchiveJob::baseDirectory() const +{ + auto d = jobPrivate(this); + return d->m_baseDirectory; +} + +#include "signarchivejob.moc" diff --git a/lang/qt/src/signarchivejob.h b/lang/qt/src/signarchivejob.h new file mode 100644 index 00000000..6b8cd175 --- /dev/null +++ b/lang/qt/src/signarchivejob.h @@ -0,0 +1,88 @@ +/* + signarchivejob.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_SIGNARCHIVEJOB_H__ +#define __QGPGME_SIGNARCHIVEJOB_H__ + +#include "job.h" + +#ifdef BUILDING_QGPGME +# include "context.h" +#else +# include +#endif + +namespace GpgME +{ +class Key; +} + +namespace QGpgME +{ + +/** + * Abstract base class for job for creating signed archives + */ +class QGPGME_EXPORT SignArchiveJob : public Job +{ + Q_OBJECT +protected: + explicit SignArchiveJob(QObject *parent); +public: + ~SignArchiveJob() override; + + void setBaseDirectory(const QString &baseDirectory); + QString baseDirectory() const; + + /** + * Starts the creation of a signed archive. + * + * Creates a signed archive with the files and directories in \a paths. + * The archive is signed with the keys in \a signers or with the default + * key, if \a signers is empty. The signed archive is written to \a output. + * + * Emits result() when the job has finished. + */ + virtual GpgME::Error start(const std::vector &signers, + const std::vector &paths, + const std::shared_ptr &output) = 0; + +Q_SIGNALS: + void result(const GpgME::SigningResult &result, + const QString &auditLogAsHtml = {}, + const GpgME::Error &auditLogError = {}); +}; + +} + +#endif // __QGPGME_SIGNARCHIVEJOB_H__ diff --git a/lang/qt/src/signarchivejob_p.h b/lang/qt/src/signarchivejob_p.h new file mode 100644 index 00000000..9176e7b4 --- /dev/null +++ b/lang/qt/src/signarchivejob_p.h @@ -0,0 +1,49 @@ +/* + signarchivejob_p.h + + This file is part of qgpgme, the Qt API binding for gpgme + Copyright (c) 2023 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 + 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_SIGNARCHIVEJOB_P_H__ +#define __QGPGME_SIGNARCHIVEJOB_P_H__ + +#include "job_p.h" + +namespace QGpgME +{ + +struct SignArchiveJobPrivate : public JobPrivate +{ + QString m_baseDirectory; +}; + +} + +#endif // __QGPGME_SIGNARCHIVEJOB_P_H__ diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am index 97e2b417..4e43d986 100644 --- a/lang/qt/tests/Makefile.am +++ b/lang/qt/tests/Makefile.am @@ -92,6 +92,7 @@ run_importjob_SOURCES = run-importjob.cpp run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp run_receivekeysjob_SOURCES = run-receivekeysjob.cpp run_refreshkeysjob_SOURCES = run-refreshkeysjob.cpp +run_signarchivejob_SOURCES = run-signarchivejob.cpp nodist_t_keylist_SOURCES = $(moc_files) @@ -104,7 +105,9 @@ noinst_PROGRAMS = \ t-trustsignatures t-changeexpiryjob t-wkdlookup t-import t-revokekey \ t-setprimaryuserid \ run-encryptarchivejob \ - run-importjob run-exportjob run-receivekeysjob run-refreshkeysjob + run-importjob run-exportjob run-receivekeysjob run-refreshkeysjob \ + run-signarchivejob + 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-signarchivejob.cpp b/lang/qt/tests/run-signarchivejob.cpp new file mode 100644 index 00000000..c426ba93 --- /dev/null +++ b/lang/qt/tests/run-signarchivejob.cpp @@ -0,0 +1,145 @@ +/* + run-signarchivejob.cpp + + This file is part of QGpgME's test suite. + Copyright (c) 2023 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 +#include + +#include +#include + +#include + +using namespace GpgME; + +std::ostream &operator<<(std::ostream &os, const QString &s) +{ + return os << s.toLocal8Bit().constData(); +} + +struct CommandLineOptions { + bool armor; + QString archiveName; + QString baseDirectory; + std::vector filesAndDirectories; +}; + +CommandLineOptions parseCommandLine(const QStringList &arguments) +{ + CommandLineOptions options; + + QCommandLineParser parser; + parser.setApplicationDescription("Test program for SignArchiveJob"); + parser.addHelpOption(); + parser.addOptions({ + {{"o", "output"}, "Write output to FILE.", "FILE"}, + {{"a", "armor"}, "Create ASCII armored output."}, + {{"C", "directory"}, "Change to DIRECTORY before creating the archive.", "DIRECTORY"}, + }); + parser.addPositionalArgument("files", "Files and directories to add to the archive", "[files] [directories]"); + + parser.process(arguments); + + const auto args = parser.positionalArguments(); + if (args.empty()) { + parser.showHelp(1); + } + + options.armor = parser.isSet("armor"); + options.archiveName = parser.value("output"); + options.baseDirectory = parser.value("directory"); + std::copy(args.begin(), args.end(), std::back_inserter(options.filesAndDirectories)); + + return options; +} + +std::shared_ptr createOutput(const QString &fileName) +{ + std::shared_ptr output; + + if (fileName.isEmpty()) { + output.reset(new QFile); + output->open(stdout, QIODevice::WriteOnly); + } else { + if (QFile::exists(fileName)) { + qCritical() << "File" << fileName << "exists. Bailing out."; + } else { + output.reset(new QFile{fileName}); + output->open(QIODevice::WriteOnly); + } + } + + return output; +} + +int main(int argc, char **argv) +{ + GpgME::initializeLibrary(); + + QCoreApplication app{argc, argv}; + app.setApplicationName("run-signarchivejob"); + + const auto options = parseCommandLine(app.arguments()); + + auto output = createOutput(options.archiveName); + if (!output) { + return 1; + } + + auto job = QGpgME::openpgp()->signArchiveJob(options.armor); + if (!job) { + std::cerr << "Error: Could not create job" << std::endl; + return 1; + } + job->setBaseDirectory(options.baseDirectory); + QObject::connect(job, &QGpgME::SignArchiveJob::result, &app, [](const GpgME::SigningResult &result, const QString &auditLog, const GpgME::Error &) { + std::cerr << "Diagnostics: " << auditLog << std::endl; + std::cerr << "Result: " << result << std::endl; + qApp->quit(); + }); + + const auto err = job->start({}, options.filesAndDirectories, output); + if (err) { + std::cerr << "Error: Starting the job failed: " << err.asString() << std::endl; + return 1; + } + + return app.exec(); +} -- cgit