aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lang/qt/src/Makefile.am11
-rw-r--r--lang/qt/src/job.cpp3
-rw-r--r--lang/qt/src/protocol.h4
-rw-r--r--lang/qt/src/protocol_p.h13
-rw-r--r--lang/qt/src/qgpgmewkdlookupjob.cpp182
-rw-r--r--lang/qt/src/qgpgmewkdlookupjob.h70
-rw-r--r--lang/qt/src/wkdlookupjob.h78
-rw-r--r--lang/qt/src/wkdlookupresult.cpp111
-rw-r--r--lang/qt/src/wkdlookupresult.h83
-rw-r--r--lang/qt/tests/Makefile.am16
-rwxr-xr-xlang/qt/tests/final.test6
-rw-r--r--lang/qt/tests/t-support.h10
-rw-r--r--lang/qt/tests/t-wkdlookup.cpp148
13 files changed, 727 insertions, 8 deletions
diff --git a/lang/qt/src/Makefile.am b/lang/qt/src/Makefile.am
index 2c8976ba..261eff60 100644
--- a/lang/qt/src/Makefile.am
+++ b/lang/qt/src/Makefile.am
@@ -36,12 +36,12 @@ qgpgme_sources = \
qgpgmerefreshkeysjob.cpp \
qgpgmesecretkeyexportjob.cpp qgpgmesignencryptjob.cpp \
qgpgmesignjob.cpp qgpgmesignkeyjob.cpp qgpgmeverifydetachedjob.cpp \
- qgpgmeverifyopaquejob.cpp threadedjobmixin.cpp \
+ qgpgmeverifyopaquejob.cpp qgpgmewkdlookupjob.cpp threadedjobmixin.cpp \
qgpgmekeyformailboxjob.cpp qgpgme_debug.cpp \
qgpgmetofupolicyjob.cpp qgpgmequickjob.cpp \
defaultkeygenerationjob.cpp qgpgmewkspublishjob.cpp \
qgpgmegpgcardjob.cpp changeexpiryjob.cpp \
- dn.cpp cryptoconfig.cpp
+ dn.cpp cryptoconfig.cpp wkdlookupresult.cpp
# If you add one here make sure that you also add one in camelcase
qgpgme_headers= \
@@ -81,6 +81,8 @@ qgpgme_headers= \
verifydetachedjob.h \
defaultkeygenerationjob.h \
tofupolicyjob.h \
+ wkdlookupjob.h \
+ wkdlookupresult.h \
wkspublishjob.h \
gpgcardjob.h \
dn.h
@@ -121,6 +123,8 @@ camelcase_headers= \
VerifyDetachedJob \
KeyForMailboxJob \
DefaultKeyGenerationJob \
+ WKDLookupJob \
+ WKDLookupResult \
WKSPublishJob \
TofuPolicyJob \
GpgCardJob
@@ -152,6 +156,7 @@ private_qgpgme_headers = \
qgpgmesignkeyjob.h \
qgpgmeverifydetachedjob.h \
qgpgmeverifyopaquejob.h \
+ qgpgmewkdlookupjob.h \
qgpgmekeyformailboxjob.h \
qgpgmewkspublishjob.h \
qgpgmetofupolicyjob.h \
@@ -201,6 +206,7 @@ qgpgme_moc_sources = \
qgpgmesignkeyjob.moc \
qgpgmeverifydetachedjob.moc \
qgpgmeverifyopaquejob.moc \
+ qgpgmewkdlookupjob.moc \
qgpgmewkspublishjob.moc \
tofupolicyjob.moc \
qgpgmetofupolicyjob.moc \
@@ -211,6 +217,7 @@ qgpgme_moc_sources = \
specialjob.moc \
verifydetachedjob.moc \
verifyopaquejob.moc \
+ wkdlookupjob.moc \
keyformailboxjob.moc \
wkspublishjob.moc \
qgpgmekeyformailboxjob.moc \
diff --git a/lang/qt/src/job.cpp b/lang/qt/src/job.cpp
index c346a355..be637a6d 100644
--- a/lang/qt/src/job.cpp
+++ b/lang/qt/src/job.cpp
@@ -64,6 +64,7 @@
#include "adduseridjob.h"
#include "specialjob.h"
#include "keyformailboxjob.h"
+#include "wkdlookupjob.h"
#include "wkspublishjob.h"
#include "tofupolicyjob.h"
#include "threadedjobmixin.h"
@@ -161,6 +162,7 @@ make_job_subclass(RefreshKeysJob)
make_job_subclass(AddUserIDJob)
make_job_subclass(SpecialJob)
make_job_subclass(KeyForMailboxJob)
+make_job_subclass(WKDLookupJob)
make_job_subclass(WKSPublishJob)
make_job_subclass(TofuPolicyJob)
make_job_subclass(QuickJob)
@@ -194,6 +196,7 @@ make_job_subclass(GpgCardJob)
#include "adduseridjob.moc"
#include "specialjob.moc"
#include "keyformailboxjob.moc"
+#include "wkdlookupjob.moc"
#include "wkspublishjob.moc"
#include "tofupolicyjob.moc"
#include "quickjob.moc"
diff --git a/lang/qt/src/protocol.h b/lang/qt/src/protocol.h
index dcc7ade4..cffd53b2 100644
--- a/lang/qt/src/protocol.h
+++ b/lang/qt/src/protocol.h
@@ -64,6 +64,7 @@ class ChangePasswdJob;
class AddUserIDJob;
class SpecialJob;
class KeyForMailboxJob;
+class WKDLookupJob;
class WKSPublishJob;
class TofuPolicyJob;
class QuickJob;
@@ -155,6 +156,9 @@ public:
/** Find the best key to use for a mailbox. */
virtual KeyForMailboxJob *keyForMailboxJob() const = 0;
+ /** This job looks up a key via WKD without importing it. */
+ virtual WKDLookupJob *wkdLookupJob() const = 0;
+
/** A Job for interacting with gnupg's wks tools. */
virtual WKSPublishJob *wksPublishJob() const = 0;
diff --git a/lang/qt/src/protocol_p.h b/lang/qt/src/protocol_p.h
index 57c1ed81..da5ce011 100644
--- a/lang/qt/src/protocol_p.h
+++ b/lang/qt/src/protocol_p.h
@@ -58,6 +58,7 @@
#include "qgpgmechangepasswdjob.h"
#include "qgpgmeadduseridjob.h"
#include "qgpgmekeyformailboxjob.h"
+#include "qgpgmewkdlookupjob.h"
#include "qgpgmewkspublishjob.h"
#include "qgpgmetofupolicyjob.h"
#include "qgpgmequickjob.h"
@@ -392,6 +393,18 @@ public:
return new QGpgME::QGpgMEKeyForMailboxJob(context);
}
+ QGpgME::WKDLookupJob *wkdLookupJob() const Q_DECL_OVERRIDE
+ {
+ if (mProtocol != GpgME::OpenPGP) {
+ return nullptr;
+ }
+ auto context = GpgME::Context::createForEngine(GpgME::AssuanEngine);
+ if (!context) {
+ return nullptr;
+ }
+ return new QGpgME::QGpgMEWKDLookupJob(context.release());
+ }
+
QGpgME::WKSPublishJob *wksPublishJob() const Q_DECL_OVERRIDE
{
if (mProtocol != GpgME::OpenPGP) {
diff --git a/lang/qt/src/qgpgmewkdlookupjob.cpp b/lang/qt/src/qgpgmewkdlookupjob.cpp
new file mode 100644
index 00000000..fcb757e1
--- /dev/null
+++ b/lang/qt/src/qgpgmewkdlookupjob.cpp
@@ -0,0 +1,182 @@
+/*
+ qgpgmewkdlookupjob.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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 "qgpgmewkdlookupjob.h"
+
+#include "qgpgme_debug.h"
+
+#include <gpgme++/context.h>
+#include <gpgme++/data.h>
+#include <gpgme++/defaultassuantransaction.h>
+
+#include <gpg-error.h>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+QGpgMEWKDLookupJob::QGpgMEWKDLookupJob(Context *context)
+ : mixin_type{context}
+{
+ lateInitialization();
+}
+
+QGpgMEWKDLookupJob::~QGpgMEWKDLookupJob() = default;
+
+static GpgME::Error startDirmngr(Context *assuanCtx)
+{
+ Error err;
+
+ auto spawnCtx = std::unique_ptr<Context>{Context::createForEngine(SpawnEngine, &err)};
+ if (err) {
+ qCDebug(QGPGME_LOG) << "Error: Failed to get context for spawn engine (" << err.asString() << ")";
+ }
+
+ const auto dirmngrProgram = GpgME::dirInfo("dirmngr-name");
+ const auto homedir = GpgME::dirInfo("homedir");
+ const char *argv[] = {
+ dirmngrProgram,
+ "--homedir",
+ homedir,
+ "--daemon",
+ NULL
+ };
+ auto ignoreIO = Data{Data::null};
+ if (!err) {
+ qCDebug(QGPGME_LOG) << "Starting dirmngr ...";
+ err = spawnCtx->spawnAsync(dirmngrProgram, argv,
+ ignoreIO, ignoreIO, ignoreIO,
+ Context::SpawnDetached);
+ }
+
+ if (!err) {
+ // wait for socket to become available
+ int cnt = 0;
+ do {
+ ++cnt;
+ qCDebug(QGPGME_LOG) << "Waiting for dirmngr to start ...";
+ QThread::msleep(250 * cnt);
+ err = assuanCtx->assuanTransact("GETINFO version");
+ } while (err.code() == GPG_ERR_ASS_CONNECT_FAILED && cnt < 5);
+ }
+
+ return err;
+}
+
+static GpgME::Error setUpDirmngrAssuanConnection(Context *ctx)
+{
+ Error err;
+
+ const std::string dirmngrSocket = GpgME::dirInfo("dirmngr-socket");
+ err = ctx->setEngineFileName(dirmngrSocket.c_str());
+
+ if (!err) {
+ err = ctx->setEngineHomeDirectory("");
+ }
+
+ if (!err) {
+ // try do connect to dirmngr
+ err = ctx->assuanTransact("GETINFO version");
+ if (err.code() == GPG_ERR_ASS_CONNECT_FAILED) {
+ err = startDirmngr(ctx);
+ }
+ }
+
+ return err;
+}
+
+static GpgME::Error run_wkd_get(Context *ctx, const QString &email)
+{
+ Error err;
+
+ const auto cmd = std::string{"WKD_GET "} + email.toUtf8().toStdString();
+ err = ctx->assuanTransact(cmd.c_str());
+ if (err.code() == GPG_ERR_NO_NAME || err.code() == GPG_ERR_NO_DATA) {
+ // ignore those benign errors; GPG_ERR_NO_NAME indicates that the domain
+ // doesn't exist (on first request); GPG_ERR_NO_DATA indicates that
+ // no key for email is available via WKD or that the domain doesn't
+ // support WKD or that the domain doesn't exist (on subsequent requests
+ // using dirmngr's internal cache)
+ qCDebug(QGPGME_LOG) << "WKD_GET returned" << err.asString() << "; ignoring...";
+ err = {};
+ }
+ if (err) {
+ qCDebug(QGPGME_LOG) << "WKD_GET failed with" << err.asString();
+ }
+
+ return err;
+}
+
+static QGpgMEWKDLookupJob::result_type lookup_keys(Context *ctx, const QString &email)
+{
+ WKDLookupResult result;
+
+ Error err = setUpDirmngrAssuanConnection(ctx);
+
+ if (!err) {
+ err = run_wkd_get(ctx, email);
+ }
+
+ if (!err) {
+ const auto transaction = std::unique_ptr<DefaultAssuanTransaction>(dynamic_cast<DefaultAssuanTransaction*>(ctx->takeLastAssuanTransaction().release()));
+ const auto source = transaction->firstStatusLine("SOURCE");
+ const auto rawData = transaction->data();
+ if (rawData.size() == 0) {
+ qCDebug(QGPGME_LOG) << "No key found for" << email;
+ result = WKDLookupResult{GpgME::Data::null, {}, {}};
+ } else {
+ qCDebug(QGPGME_LOG) << "Found key for" << email << "at" << source.c_str();
+ result = WKDLookupResult{GpgME::Data{rawData.c_str(), rawData.size()}, source, {}};
+ }
+ }
+
+ return std::make_tuple(err ? WKDLookupResult{err} : result, QString{}, Error{});
+}
+
+Error QGpgMEWKDLookupJob::start(const QString &email)
+{
+ run(std::bind(&lookup_keys, std::placeholders::_1, email));
+ return Error();
+}
+
+WKDLookupResult QGpgMEWKDLookupJob::exec(const QString &email)
+{
+ const result_type r = lookup_keys(context(), email);
+ resultHook(r);
+ return std::get<0>(r);
+}
+
+#include "qgpgmewkdlookupjob.moc"
diff --git a/lang/qt/src/qgpgmewkdlookupjob.h b/lang/qt/src/qgpgmewkdlookupjob.h
new file mode 100644
index 00000000..61f9465c
--- /dev/null
+++ b/lang/qt/src/qgpgmewkdlookupjob.h
@@ -0,0 +1,70 @@
+/*
+ qgpgmewkdlookupjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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_QGPGMEWKDLOOKUPJOB_H__
+#define __QGPGME_QGPGMEWKDLOOKUPJOB_H__
+
+#include "threadedjobmixin.h"
+#include "wkdlookupjob.h"
+#include "wkdlookupresult.h"
+
+namespace QGpgME
+{
+class WKDLookupResult;
+
+class QGpgMEWKDLookupJob
+#ifdef Q_MOC_RUN
+ : public WKDLookupJob
+#else
+ : public _detail::ThreadedJobMixin<WKDLookupJob, std::tuple<WKDLookupResult, QString, GpgME::Error> >
+#endif
+{
+ Q_OBJECT
+#ifdef Q_MOC_RUN
+public Q_SLOTS:
+ void slotFinished();
+#endif
+public:
+ explicit QGpgMEWKDLookupJob(GpgME::Context *context);
+ ~QGpgMEWKDLookupJob();
+
+ /* from WKDLookupJob */
+ GpgME::Error start(const QString &email) Q_DECL_OVERRIDE;
+
+ /* from WKDLookupJob */
+ WKDLookupResult exec(const QString &email) Q_DECL_OVERRIDE;
+};
+
+}
+
+#endif // __QGPGME_QGPGMEWKDLOOKUPJOB_H__
diff --git a/lang/qt/src/wkdlookupjob.h b/lang/qt/src/wkdlookupjob.h
new file mode 100644
index 00000000..ae228744
--- /dev/null
+++ b/lang/qt/src/wkdlookupjob.h
@@ -0,0 +1,78 @@
+/*
+ wkdlookupjob.h
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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_WKDLOOKUPJOB_H__
+#define __QGPGME_WKDLOOKUPJOB_H__
+
+#include "job.h"
+#include "qgpgme_export.h"
+
+class QString;
+
+namespace GpgME
+{
+class Data;
+class Error;
+}
+
+namespace QGpgME
+{
+
+class WKDLookupResult;
+
+class QGPGME_EXPORT WKDLookupJob : public Job
+{
+ Q_OBJECT
+protected:
+ explicit WKDLookupJob(QObject *parent);
+
+public:
+ ~WKDLookupJob();
+
+ /**
+ Starts a key lookup operation for the email address \a email via WKD.
+ */
+ virtual GpgME::Error start(const QString &email) = 0;
+
+ /**
+ Runs a key lookup operation for the email address \a email via WKD.
+ */
+ virtual WKDLookupResult exec(const QString &email) = 0;
+
+Q_SIGNALS:
+ void result(const WKDLookupResult &result, const QString &auditLogAsHtml = {}, const GpgME::Error &auditLogError = {});
+};
+
+}
+
+#endif // __QGPGME_WKDLOOKUPJOB_H__
diff --git a/lang/qt/src/wkdlookupresult.cpp b/lang/qt/src/wkdlookupresult.cpp
new file mode 100644
index 00000000..71aa75cf
--- /dev/null
+++ b/lang/qt/src/wkdlookupresult.cpp
@@ -0,0 +1,111 @@
+/*
+ wkdlookupresult.cpp - wraps the result of a WKDLookupJob
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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 "wkdlookupresult.h"
+
+#include <gpgme++/data.h>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+class WKDLookupResult::Private
+{
+public:
+ GpgME::Data keyData;
+ std::string source;
+};
+
+WKDLookupResult::WKDLookupResult() = default;
+
+WKDLookupResult::~WKDLookupResult() = default;
+
+WKDLookupResult::WKDLookupResult(const Error &error)
+ : Result{error}
+ , d{}
+{
+}
+
+WKDLookupResult::WKDLookupResult(const Data &keyData, const std::string &source, const Error &error)
+ : Result{error}
+ , d{new Private{keyData, source}}
+{
+}
+
+WKDLookupResult::WKDLookupResult(const WKDLookupResult &other)
+ : Result{other}
+{
+ if (other.d) {
+ d.reset(new Private{*other.d});
+ }
+}
+
+WKDLookupResult &WKDLookupResult::operator=(const WKDLookupResult &other)
+{
+ auto tmp = other;
+ swap(tmp);
+ return *this;
+}
+
+WKDLookupResult::WKDLookupResult(WKDLookupResult &&other) = default;
+
+WKDLookupResult &WKDLookupResult::operator=(WKDLookupResult &&other) = default;
+
+void WKDLookupResult::swap(WKDLookupResult &other) noexcept
+{
+ Result::swap(other);
+ std::swap(this->d, other.d);
+}
+
+bool WKDLookupResult::isNull() const
+{
+ return !d && !bool(error());
+}
+
+Data WKDLookupResult::keyData() const
+{
+ return d ? d->keyData : Data{};
+}
+
+std::string WKDLookupResult::source() const
+{
+ return d ? d->source : std::string{};
+}
+
+void QGpgME::swap(WKDLookupResult &a, WKDLookupResult &b)
+{
+ a.swap(b);
+}
diff --git a/lang/qt/src/wkdlookupresult.h b/lang/qt/src/wkdlookupresult.h
new file mode 100644
index 00000000..c40220a6
--- /dev/null
+++ b/lang/qt/src/wkdlookupresult.h
@@ -0,0 +1,83 @@
+/*
+ wkdlookupresult.h - wraps the result of a WKDLookupJob
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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_WKDLOOKUPRESULT_H__
+#define __QGPGME_WKDLOOKUPRESULT_H__
+
+#include "qgpgme_export.h"
+
+#include <gpgme++/result.h>
+
+#include <memory>
+
+namespace GpgME
+{
+class Data;
+class Error;
+}
+
+namespace QGpgME
+{
+
+class QGPGME_EXPORT WKDLookupResult : public GpgME::Result
+{
+public:
+ WKDLookupResult();
+ ~WKDLookupResult();
+
+ explicit WKDLookupResult(const GpgME::Error &err);
+ explicit WKDLookupResult(const GpgME::Data &keyData, const std::string &source, const GpgME::Error &err);
+
+ WKDLookupResult(const WKDLookupResult &other);
+ WKDLookupResult &operator=(const WKDLookupResult &other);
+
+ WKDLookupResult(WKDLookupResult &&other);
+ WKDLookupResult &operator=(WKDLookupResult &&other);
+
+ void swap(WKDLookupResult &other) noexcept;
+
+ bool isNull() const;
+
+ GpgME::Data keyData() const;
+ std::string source() const;
+
+private:
+ class Private;
+ std::unique_ptr<Private> d;
+};
+
+QGPGME_EXPORT void swap(WKDLookupResult &a, WKDLookupResult &b);
+
+}
+
+#endif // __QGPGME_WKDLOOKUPRESULT_H__
diff --git a/lang/qt/tests/Makefile.am b/lang/qt/tests/Makefile.am
index 8c44681b..b7ec546e 100644
--- a/lang/qt/tests/Makefile.am
+++ b/lang/qt/tests/Makefile.am
@@ -24,16 +24,19 @@ GPG = gpg
GNUPGHOME=$(abs_builddir)
TESTS_ENVIRONMENT = GNUPGHOME=$(GNUPGHOME)
-EXTRA_DIST = initial.test
+EXTRA_DIST = initial.test final.test
-TESTS = initial.test t-keylist t-keylocate t-ownertrust t-tofuinfo \
- t-encrypt t-verify t-various t-config t-remarks t-trustsignatures \
- t-changeexpiryjob
+the_tests = \
+ t-keylist t-keylocate t-ownertrust t-tofuinfo \
+ t-encrypt t-verify t-various t-config t-remarks t-trustsignatures \
+ t-changeexpiryjob t-wkdlookup
+
+TESTS = initial.test $(the_tests) final.test
moc_files = t-keylist.moc t-keylocate.moc t-ownertrust.moc t-tofuinfo.moc \
t-encrypt.moc t-support.hmoc t-wkspublish.moc t-verify.moc \
t-various.moc t-config.moc t-remarks.moc t-trustsignatures.moc \
- t-changeexpiryjob.moc
+ t-changeexpiryjob.moc t-wkdlookup.moc
AM_LDFLAGS = -no-install
@@ -61,6 +64,7 @@ t_config_SOURCES = t-config.cpp $(support_src)
t_remarks_SOURCES = t-remarks.cpp $(support_src)
t_trustsignatures_SOURCES = t-trustsignatures.cpp $(support_src)
t_changeexpiryjob_SOURCES = t-changeexpiryjob.cpp $(support_src)
+t_wkdlookup_SOURCES = t-wkdlookup.cpp $(support_src)
run_keyformailboxjob_SOURCES = run-keyformailboxjob.cpp
nodist_t_keylist_SOURCES = $(moc_files)
@@ -69,7 +73,7 @@ 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-trustsignatures t-changeexpiryjob t-wkdlookup
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/final.test b/lang/qt/tests/final.test
new file mode 100755
index 00000000..f28aaa4c
--- /dev/null
+++ b/lang/qt/tests/final.test
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# stop the dirmngr that may have been started
+gpgconf --kill dirmngr
+
+exit 0
diff --git a/lang/qt/tests/t-support.h b/lang/qt/tests/t-support.h
index 77bef56d..22ba473c 100644
--- a/lang/qt/tests/t-support.h
+++ b/lang/qt/tests/t-support.h
@@ -34,9 +34,19 @@
#include "interfaces/passphraseprovider.h"
#include <QObject>
+#include <QTest>
#include <gpg-error.h>
+namespace QTest
+{
+template <>
+inline char *toString(const std::string &s)
+{
+ return QTest::toString(s.c_str());
+}
+}
+
namespace GpgME
{
class TestPassphraseProvider : public PassphraseProvider
diff --git a/lang/qt/tests/t-wkdlookup.cpp b/lang/qt/tests/t-wkdlookup.cpp
new file mode 100644
index 00000000..13c70269
--- /dev/null
+++ b/lang/qt/tests/t-wkdlookup.cpp
@@ -0,0 +1,148 @@
+/* t-wkdlookup.cpp
+
+ This file is part of qgpgme, the Qt API binding for gpgme
+ Copyright (c) 2021 g10 Code GmbH
+ Software engineering by Ingo Klöcker <[email protected]>
+
+ 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 "t-support.h"
+
+#include "data.h"
+#include "engineinfo.h"
+#include "protocol.h"
+#include "wkdlookupjob.h"
+#include "wkdlookupresult.h"
+
+#include <QDebug>
+#include <QSignalSpy>
+#include <QTest>
+
+#include <algorithm>
+
+using namespace QGpgME;
+using namespace GpgME;
+
+static const char *requiredVersion = "2.1.12";
+
+namespace
+{
+bool keyHasUserIDWithMatchingEmailAddress(const Key &key, const QString &expectedEmailAddress)
+{
+ const auto email = expectedEmailAddress.toLower();
+ const auto userIds = key.userIDs();
+ return std::any_of(
+ std::begin(userIds), std::end(userIds),
+ [email](const UserID &uid) {
+ return email == QString::fromUtf8(uid.email()).toLower();
+ });
+}
+}
+
+class WKDLookupTest : public QGpgMETest
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void asyncDone();
+
+private Q_SLOTS:
+
+#ifndef DO_ONLINE_TESTS
+ void testWKDLookupAsync()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < requiredVersion) {
+ QSKIP("dirmngr does not yet support WKD lookup");
+ }
+ const QString email = QLatin1String{"[email protected]"};
+
+ WKDLookupResult result;
+ auto *job = openpgp()->wkdLookupJob();
+ connect(job, &WKDLookupJob::result, job, [this, &result](const WKDLookupResult &result_, const QString &, const Error &)
+ {
+ result = result_;
+ Q_EMIT asyncDone();
+ });
+ job->start(email);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT));
+
+ QVERIFY(result.error().code() == GPG_ERR_NO_ERROR);
+ QCOMPARE(result.source(), "https://openpgpkey.gnupg.org");
+ const auto keys = result.keyData().toKeys(GpgME::OpenPGP);
+ QVERIFY(keys.size() == 1);
+ QVERIFY(keyHasUserIDWithMatchingEmailAddress(keys.front(), email));
+ }
+
+ void testWKDLookupSync()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < requiredVersion) {
+ QSKIP("dirmngr does not yet support WKD lookup");
+ }
+ const QString email = QLatin1String{"[email protected]"};
+
+ auto *job = openpgp()->wkdLookupJob();
+ const auto result = job->exec(email);
+
+ QVERIFY(result.error().code() == GPG_ERR_NO_ERROR);
+ QCOMPARE(result.source(), "https://openpgpkey.gnupg.org");
+ const auto keys = result.keyData().toKeys(GpgME::OpenPGP);
+ QVERIFY(keys.size() == 1);
+ QVERIFY(keyHasUserIDWithMatchingEmailAddress(keys.front(), email));
+ }
+
+ void testLookupWithNoResultAsync()
+ {
+ if (GpgME::engineInfo(GpgME::GpgEngine).engineVersion() < requiredVersion) {
+ QSKIP("dirmngr does not yet support WKD lookup");
+ }
+ const QString email = QLatin1String{"[email protected]"};
+
+ WKDLookupResult result;
+ auto *job = openpgp()->wkdLookupJob();
+ connect(job, &WKDLookupJob::result, job, [this, &result](const WKDLookupResult &result_, const QString &, const Error &)
+ {
+ result = result_;
+ Q_EMIT asyncDone();
+ });
+ job->start(email);
+ QSignalSpy spy (this, SIGNAL(asyncDone()));
+ QVERIFY(spy.wait(QSIGNALSPY_TIMEOUT));
+
+ QVERIFY(result.error().code() == GPG_ERR_NO_ERROR);
+ QCOMPARE(result.source(), "");
+ QVERIFY(result.keyData().isNull());
+ }
+#endif
+};
+
+QTEST_MAIN(WKDLookupTest)
+
+#include "t-wkdlookup.moc"