diff --git a/lang/qt/src/qgpgmerevokekeyjob.cpp b/lang/qt/src/qgpgmerevokekeyjob.cpp index 08585414..8a2c224e 100644 --- a/lang/qt/src/qgpgmerevokekeyjob.cpp +++ b/lang/qt/src/qgpgmerevokekeyjob.cpp @@ -46,6 +46,8 @@ #include +#include "qgpgme_debug.h" + using namespace QGpgME; using namespace GpgME; @@ -57,6 +59,29 @@ QGpgMERevokeKeyJob::QGpgMERevokeKeyJob(Context *context) QGpgMERevokeKeyJob::~QGpgMERevokeKeyJob() = default; + +static Error check_arguments(const Key &key, + RevocationReason reason, + const std::vector &description) +{ + if (key.isNull()) { + qWarning(QGPGME_LOG) << "Error: Key is null key"; + return Error::fromCode(GPG_ERR_INV_ARG); + } + if (reason < RevocationReason::Unspecified || reason > RevocationReason::NoLongerUsed) { + qWarning(QGPGME_LOG) << "Error: Invalid revocation reason" << static_cast(reason); + return Error::fromCode(GPG_ERR_INV_VALUE); + } + if (std::any_of(std::begin(description), std::end(description), + [](const std::string &line) { + return line.empty() || line.find('\n') != std::string::npos; + })) { + qWarning(QGPGME_LOG) << "Error: Revocation description contains empty lines or lines with endline characters"; + return Error::fromCode(GPG_ERR_INV_VALUE); + } + return {}; +} + static QGpgMERevokeKeyJob::result_type revoke_key(Context *ctx, const Key &key, RevocationReason reason, const std::vector &description) @@ -80,17 +105,24 @@ Error QGpgMERevokeKeyJob::start(const GpgME::Key &key, GpgME::RevocationReason reason, const std::vector &description) { - run(std::bind(&revoke_key, std::placeholders::_1, key, reason, description)); - return {}; + Error err = check_arguments(key, reason, description); + if (!err) { + run(std::bind(&revoke_key, std::placeholders::_1, key, reason, description)); + } + return err; } Error QGpgMERevokeKeyJob::exec(const GpgME::Key &key, GpgME::RevocationReason reason, const std::vector &description) { - const result_type r = revoke_key(context(), key, reason, description); - resultHook(r); - return std::get<0>(r); + Error err = check_arguments(key, reason, description); + if (!err) { + const result_type r = revoke_key(context(), key, reason, description); + resultHook(r); + err = std::get<0>(r); + } + return err; } #include "qgpgmerevokekeyjob.moc" diff --git a/lang/qt/tests/t-revokekey.cpp b/lang/qt/tests/t-revokekey.cpp index 6586f093..9aec5753 100644 --- a/lang/qt/tests/t-revokekey.cpp +++ b/lang/qt/tests/t-revokekey.cpp @@ -39,6 +39,7 @@ #include #include +#include #include #include @@ -196,6 +197,66 @@ private Q_SLOTS: "0000 1111 2222 3333 4444 5555 6666 7777 8888 9999."}); } + void testErrorHandling_nullKey() + { + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, "Error: Key is null key"); + const auto result = job->exec(Key{}); + QVERIFY(result.code() == GPG_ERR_INV_ARG); + } + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, "Error: Key is null key"); + const auto result = job->start(Key{}); + QVERIFY(result.code() == GPG_ERR_INV_ARG); + } + } + + void testErrorHandling_invalidReason() + { + // Get the key that shall be revoked + auto key = getTestKey("revoke-me@example.net"); + QVERIFY(!key.isNull()); + QVERIFY(!key.isRevoked()); + + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression{"^Error: Invalid revocation reason"}); + const auto result = job->exec(key, static_cast(-1)); + QVERIFY(result.code() == GPG_ERR_INV_VALUE); + } + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, QRegularExpression{"^Error: Invalid revocation reason"}); + const auto result = job->start(key, static_cast(4)); + QVERIFY(result.code() == GPG_ERR_INV_VALUE); + } + } + + void testErrorHandling_invalidDescription() + { + // Get the key that shall be revoked + auto key = getTestKey("revoke-me@example.net"); + QVERIFY(!key.isNull()); + QVERIFY(!key.isRevoked()); + + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, "Error: Revocation description contains empty lines or lines with endline characters"); + const auto result = job->exec(key, RevocationReason::Unspecified, + {"line1", "", "line3"}); + QVERIFY(result.code() == GPG_ERR_INV_VALUE); + } + { + auto job = std::unique_ptr{openpgp()->revokeKeyJob()}; + QTest::ignoreMessage(QtWarningMsg, "Error: Revocation description contains empty lines or lines with endline characters"); + const auto result = job->start(key, RevocationReason::Unspecified, + {"line1\nline2"}); + QVERIFY(result.code() == GPG_ERR_INV_VALUE); + } + } + private: Key getTestKey(const char *pattern) {