File indexing completed on 2024-12-22 05:05:17

0001 // SPDX-FileCopyrightText: 2016 Sandro Knauß <knauss@kolabsystems.com>
0002 // SPDX-License-Identifier: LGPL-2.0-or-later
0003 
0004 #include <MimeTreeParserCore/ObjectTreeParser>
0005 
0006 #include <gpgme.h>
0007 
0008 #include <QProcess>
0009 #include <QTest>
0010 
0011 QByteArray readMailFromFile(const QString &mailFile)
0012 {
0013     QFile file(QLatin1StringView(MAIL_DATA_DIR) + QLatin1Char('/') + mailFile);
0014     file.open(QIODevice::ReadOnly);
0015     Q_ASSERT(file.isOpen());
0016     return file.readAll();
0017 }
0018 
0019 void killAgent(const QString &dir)
0020 {
0021     QProcess proc;
0022     proc.setProgram(QStringLiteral("gpg-connect-agent"));
0023     QStringList arguments;
0024     arguments << QStringLiteral("-S ") << dir + QStringLiteral("/S.gpg-agent");
0025     proc.start();
0026     proc.waitForStarted();
0027     proc.write("KILLAGENT\n");
0028     proc.write("BYE\n");
0029     proc.closeWriteChannel();
0030     proc.waitForFinished();
0031 }
0032 
0033 class GpgErrorTest : public QObject
0034 {
0035     Q_OBJECT
0036 
0037 private Q_SLOTS:
0038 
0039     void testGpgConfiguredCorrectly()
0040     {
0041         setEnv("GNUPGHOME", GNUPGHOME);
0042 
0043         MimeTreeParser::ObjectTreeParser otp;
0044         otp.parseObjectTree(readMailFromFile(QStringLiteral("openpgp-inline-charset-encrypted.mbox")));
0045         otp.print();
0046         otp.decryptAndVerify();
0047         otp.print();
0048         auto partList = otp.collectContentParts();
0049         QCOMPARE(partList.size(), 1);
0050         auto part = partList[0];
0051         QVERIFY(bool(part));
0052 
0053         QVERIFY(part->text().startsWith(QStringLiteral("asdasd")));
0054         QCOMPARE(part->encryptions().size(), 1);
0055         auto enc = part->encryptions()[0];
0056         QCOMPARE(enc->error(), MimeTreeParser::MessagePart::NoError);
0057         // QCOMPARE((int) enc->recipients().size(), 2);
0058     }
0059 
0060     void testNoGPGInstalled_data()
0061     {
0062         QTest::addColumn<QString>("mailFileName");
0063 
0064         QTest::newRow("openpgp-inline-charset-encrypted") << "openpgp-inline-charset-encrypted.mbox";
0065         QTest::newRow("openpgp-encrypted-attachment-and-non-encrypted-attachment") << "openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox";
0066         QTest::newRow("smime-encrypted") << "smime-encrypted.mbox";
0067     }
0068 
0069     void testNoGPGInstalled()
0070     {
0071         QFETCH(QString, mailFileName);
0072 
0073         setEnv("PATH", "/nonexististing");
0074         setGpgMEfname("/nonexisting/gpg", "");
0075 
0076         MimeTreeParser::ObjectTreeParser otp;
0077         otp.parseObjectTree(readMailFromFile(mailFileName));
0078         otp.print();
0079         otp.decryptAndVerify();
0080         otp.print();
0081         auto partList = otp.collectContentParts();
0082         QCOMPARE(partList.size(), 1);
0083         auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>();
0084         QVERIFY(bool(part));
0085 
0086         QCOMPARE(part->encryptions().size(), 1);
0087         QVERIFY(part->text().isEmpty());
0088         auto enc = part->encryptions()[0];
0089         QCOMPARE(enc->error(), MimeTreeParser::MessagePart::NoKeyError);
0090     }
0091 
0092     void testGpgIncorrectGPGHOME_data()
0093     {
0094         QTest::addColumn<QString>("mailFileName");
0095 
0096         QTest::newRow("openpgp-inline-charset-encrypted") << "openpgp-inline-charset-encrypted.mbox";
0097         QTest::newRow("openpgp-encrypted-attachment-and-non-encrypted-attachment") << "openpgp-encrypted-attachment-and-non-encrypted-attachment.mbox";
0098         QTest::newRow("smime-encrypted") << "smime-encrypted.mbox";
0099     }
0100 
0101     void testGpgIncorrectGPGHOME()
0102     {
0103         QFETCH(QString, mailFileName);
0104         setEnv("GNUPGHOME", QByteArray(GNUPGHOME) + QByteArray("noexist"));
0105 
0106         MimeTreeParser::ObjectTreeParser otp;
0107         otp.parseObjectTree(readMailFromFile(mailFileName));
0108         otp.print();
0109         otp.decryptAndVerify();
0110         otp.print();
0111         auto partList = otp.collectContentParts();
0112         QCOMPARE(partList.size(), 1);
0113         auto part = partList[0].dynamicCast<MimeTreeParser::MessagePart>();
0114         QVERIFY(bool(part));
0115 
0116         QCOMPARE(part->encryptions().size(), 1);
0117         QCOMPARE(part->signatures().size(), 0);
0118         QVERIFY(part->text().isEmpty());
0119         auto enc = part->encryptions()[0];
0120         QVERIFY(enc->isNoSecKey());
0121         // QCOMPARE((int) enc->recipients().size(), 2);
0122     }
0123 
0124 public Q_SLOTS:
0125     void init()
0126     {
0127         mResetGpgmeEngine = false;
0128         mModifiedEnv.clear();
0129         {
0130             gpgme_check_version(nullptr);
0131             gpgme_ctx_t ctx = nullptr;
0132             gpgme_new(&ctx);
0133             gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
0134             gpgme_engine_info_t info = gpgme_ctx_get_engine_info(ctx);
0135             mGpgmeEngine_fname = info->file_name;
0136             gpgme_release(ctx);
0137         }
0138         mEnv = QProcessEnvironment::systemEnvironment();
0139         unsetEnv("GNUPGHOME");
0140     }
0141 
0142     void cleanup()
0143     {
0144         QCoreApplication::sendPostedEvents();
0145 
0146         const QString &gnupghome = QString::fromUtf8(qgetenv("GNUPGHOME"));
0147         if (!gnupghome.isEmpty()) {
0148             killAgent(gnupghome);
0149         }
0150 
0151         resetGpgMfname();
0152         resetEnv();
0153     }
0154 
0155 private:
0156     void unsetEnv(const QByteArray &name)
0157     {
0158         mModifiedEnv << name;
0159         qunsetenv(name.data());
0160     }
0161 
0162     void setEnv(const QByteArray &name, const QByteArray &value)
0163     {
0164         mModifiedEnv << name;
0165         qputenv(name.data(), value);
0166     }
0167 
0168     void resetEnv()
0169     {
0170         for (const auto &i : std::as_const(mModifiedEnv)) {
0171             const auto env = i.data();
0172             if (mEnv.contains(QString::fromUtf8(i))) {
0173                 qputenv(env, mEnv.value(QString::fromUtf8(i)).toUtf8());
0174             } else {
0175                 qunsetenv(env);
0176             }
0177         }
0178     }
0179 
0180     void resetGpgMfname()
0181     {
0182         if (mResetGpgmeEngine) {
0183             gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, mGpgmeEngine_fname.data(), nullptr);
0184         }
0185     }
0186 
0187     void setGpgMEfname(const QByteArray &fname, const QByteArray &homedir)
0188     {
0189         mResetGpgmeEngine = true;
0190         gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, fname.data(), homedir.data());
0191     }
0192 
0193     QSet<QByteArray> mModifiedEnv;
0194     QProcessEnvironment mEnv;
0195     bool mResetGpgmeEngine;
0196     QByteArray mGpgmeEngine_fname;
0197 };
0198 
0199 QTEST_GUILESS_MAIN(GpgErrorTest)
0200 #include "gpgerrortest.moc"