File indexing completed on 2025-03-09 04:53:54

0001 /*
0002   SPDX-FileCopyrightText: 2009 Constantin Berzan <exit3219@gmail.com>
0003   SPDX-FileCopyrightText: 2009 Leo Franchi <lfranchi@kde.org>
0004 
0005   SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "cryptocomposertest.h"
0009 
0010 #include "cryptofunctions.h"
0011 #include "qtest_messagecomposer.h"
0012 
0013 #include "setupenv.h"
0014 
0015 #include <Libkleo/Enum>
0016 
0017 #include <KMime/Headers>
0018 using namespace KMime;
0019 
0020 #include <MessageComposer/AttachmentControllerBase>
0021 #include <MessageComposer/AttachmentModel>
0022 #include <MessageComposer/Composer>
0023 #include <MessageComposer/ComposerViewBase>
0024 #include <MessageComposer/GlobalPart>
0025 #include <MessageComposer/InfoPart>
0026 #include <MessageComposer/RichTextComposerNg>
0027 #include <MessageComposer/TextPart>
0028 #include <MessageComposer/Util>
0029 using namespace MessageComposer;
0030 
0031 #include <MessageCore/AttachmentPart>
0032 #include <MessageCore/NodeHelper>
0033 using namespace MessageCore;
0034 
0035 #include <MimeTreeParser/ObjectTreeParser>
0036 #include <MimeTreeParser/SimpleObjectTreeSource>
0037 
0038 #include <QGpgME/KeyListJob>
0039 #include <QGpgME/Protocol>
0040 #include <gpgme++/key.h>
0041 #include <gpgme++/keylistresult.h>
0042 
0043 #include <QDebug>
0044 #include <QTest>
0045 
0046 Q_DECLARE_METATYPE(MessageCore::AttachmentPart)
0047 
0048 QTEST_MAIN(CryptoComposerTest)
0049 
0050 void CryptoComposerTest::initTestCase()
0051 {
0052     MessageComposer::Test::setupEnv();
0053 }
0054 
0055 Q_DECLARE_METATYPE(Headers::contentEncoding)
0056 
0057 // openpgp
0058 void CryptoComposerTest::testOpenPGPMime_data()
0059 {
0060     QTest::addColumn<QString>("data");
0061     QTest::addColumn<bool>("sign");
0062     QTest::addColumn<bool>("encrypt");
0063     QTest::addColumn<Headers::contentEncoding>("cte");
0064 
0065     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0066     QTest::newRow("SignOpenPGPMime") << data << true << false << Headers::CE7Bit;
0067     QTest::newRow("EncryptOpenPGPMime") << data << false << true << Headers::CE7Bit;
0068     QTest::newRow("SignEncryptOpenPGPMime") << data << true << true << Headers::CE7Bit;
0069 }
0070 
0071 void CryptoComposerTest::testOpenPGPMime()
0072 {
0073     QFETCH(QString, data);
0074     QFETCH(bool, sign);
0075     QFETCH(bool, encrypt);
0076     QFETCH(Headers::contentEncoding, cte);
0077 
0078     auto composer = new Composer;
0079 
0080     fillComposerData(composer, data);
0081     fillComposerCryptoData(composer);
0082 
0083     composer->setSignAndEncrypt(sign, encrypt);
0084     composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0085 
0086     VERIFYEXEC(composer);
0087     QCOMPARE(composer->resultMessages().size(), 1);
0088 
0089     KMime::Message::Ptr message = composer->resultMessages().first();
0090     delete composer;
0091     composer = nullptr;
0092 
0093     // qDebug()<< "message:" << message.data()->encodedContent();
0094     ComposerTestUtil::verify(sign, encrypt, message.data(), data.toUtf8(), Kleo::OpenPGPMIMEFormat, cte);
0095 
0096     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0097     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0098 }
0099 
0100 // the following will do for s-mime as well, as the same sign/enc jobs are used
0101 void CryptoComposerTest::testEncryptSameAttachments_data()
0102 {
0103     QTest::addColumn<int>("format");
0104 
0105     QTest::newRow("OpenPGPMime") << (int)Kleo::OpenPGPMIMEFormat;
0106     // TODO: fix Inline PGP with encrypted attachments
0107     // QTest::newRow( "InlineOpenPGP" ) << (int) Kleo::InlineOpenPGPFormat;
0108 }
0109 
0110 void CryptoComposerTest::testEncryptSameAttachments()
0111 {
0112     QFETCH(int, format);
0113     auto composer = new Composer;
0114     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0115     fillComposerData(composer, data);
0116     fillComposerCryptoData(composer);
0117 
0118     AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart);
0119     attachment->setData("abc");
0120     attachment->setMimeType("x-some/x-type");
0121     attachment->setFileName(QString::fromLocal8Bit("anattachment.txt"));
0122     attachment->setEncrypted(true);
0123     attachment->setSigned(false);
0124     composer->addAttachmentPart(attachment);
0125 
0126     composer->setSignAndEncrypt(false, true);
0127     composer->setMessageCryptoFormat((Kleo::CryptoMessageFormat)format);
0128 
0129     VERIFYEXEC(composer);
0130     QCOMPARE(composer->resultMessages().size(), 1);
0131 
0132     KMime::Message::Ptr message = composer->resultMessages().constFirst();
0133     delete composer;
0134     composer = nullptr;
0135 
0136     // qDebug()<< "message:" << message.data()->encodedContent();
0137     ComposerTestUtil::verifyEncryption(message.data(), data.toUtf8(), (Kleo::CryptoMessageFormat)format, true);
0138 
0139     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0140     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0141 
0142     MimeTreeParser::SimpleObjectTreeSource testSource;
0143     testSource.setDecryptMessage(true);
0144     auto nh = new MimeTreeParser::NodeHelper;
0145     MimeTreeParser::ObjectTreeParser otp(&testSource, nh);
0146 
0147     otp.parseObjectTree(message.data());
0148     KMime::Message::Ptr unencrypted = nh->unencryptedMessage(message);
0149 
0150     KMime::Content *testAttachment = Util::findTypeInMessage(unencrypted.data(), "x-some", "x-type");
0151 
0152     QCOMPARE(testAttachment->body(), QString::fromLatin1("abc").toUtf8());
0153     QCOMPARE(testAttachment->contentDisposition()->filename(), QString::fromLatin1("anattachment.txt"));
0154 }
0155 
0156 void CryptoComposerTest::testEditEncryptAttachments_data()
0157 {
0158     QTest::addColumn<int>("format");
0159     QTest::newRow("OpenPGPMime") << (int)Kleo::OpenPGPMIMEFormat;
0160     // TODO: SMIME should also be tested
0161 }
0162 
0163 void CryptoComposerTest::testEditEncryptAttachments()
0164 {
0165     QFETCH(int, format);
0166     auto composer = new Composer;
0167     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0168     fillComposerData(composer, data);
0169     fillComposerCryptoData(composer);
0170 
0171     AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart);
0172     const QString fileName = QStringLiteral("anattachment.txt");
0173     const QByteArray fileData = "abc";
0174     attachment->setData(fileData);
0175     attachment->setMimeType("x-some/x-type");
0176     attachment->setFileName(fileName);
0177     attachment->setEncrypted(true);
0178     attachment->setSigned(false);
0179     composer->addAttachmentPart(attachment);
0180 
0181     composer->setSignAndEncrypt(false, true);
0182     composer->setMessageCryptoFormat((Kleo::CryptoMessageFormat)format);
0183 
0184     VERIFYEXEC(composer);
0185     QCOMPARE(composer->resultMessages().size(), 1);
0186 
0187     KMime::Message::Ptr message = composer->resultMessages().first();
0188     delete composer;
0189     composer = nullptr;
0190 
0191     // setup a viewer
0192     ComposerViewBase view(this, nullptr);
0193     AttachmentModel model(this);
0194     AttachmentControllerBase controller(&model, nullptr, nullptr);
0195     MessageComposer::RichTextComposerNg editor;
0196     view.setAttachmentModel(&model);
0197     view.setAttachmentController(&controller);
0198     view.setEditor(&editor);
0199 
0200     // Let's load the email to the viewer
0201     view.setMessage(message, true);
0202 
0203     QModelIndex index = model.index(0, 0);
0204     QCOMPARE(editor.toPlainText(), data);
0205     QCOMPARE(model.rowCount(), 1);
0206     QCOMPARE(model.data(index, AttachmentModel::NameRole).toString(), fileName);
0207     AttachmentPart::Ptr part = model.attachments()[0];
0208     QCOMPARE(part->data(), fileData);
0209     QCOMPARE(part->fileName(), fileName);
0210 }
0211 
0212 void CryptoComposerTest::testEditEncryptAndLateAttachments_data()
0213 {
0214     QTest::addColumn<int>("format");
0215     QTest::newRow("OpenPGPMime") << (int)Kleo::OpenPGPMIMEFormat;
0216     // TODO: SMIME should also be tested
0217 }
0218 
0219 void CryptoComposerTest::testEditEncryptAndLateAttachments()
0220 {
0221     QFETCH(int, format);
0222     auto composer = new Composer;
0223     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0224     fillComposerData(composer, data);
0225     fillComposerCryptoData(composer);
0226 
0227     AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart);
0228     const QString fileName = QStringLiteral("anattachment.txt");
0229     const QByteArray fileData = "abc";
0230     const QString fileName2 = QStringLiteral("nonencrypt.txt");
0231     const QByteArray fileData2 = "readable";
0232     attachment->setData(fileData);
0233     attachment->setMimeType("x-some/x-type");
0234     attachment->setFileName(fileName);
0235     attachment->setEncrypted(true);
0236     attachment->setSigned(false);
0237     composer->addAttachmentPart(attachment);
0238 
0239     attachment = AttachmentPart::Ptr(new AttachmentPart);
0240     attachment->setData(fileData2);
0241     attachment->setMimeType("x-some/x-type2");
0242     attachment->setFileName(fileName2);
0243     attachment->setEncrypted(false);
0244     attachment->setSigned(false);
0245     composer->addAttachmentPart(attachment);
0246 
0247     composer->setSignAndEncrypt(false, true);
0248     composer->setMessageCryptoFormat((Kleo::CryptoMessageFormat)format);
0249 
0250     VERIFYEXEC(composer);
0251     QCOMPARE(composer->resultMessages().size(), 1);
0252 
0253     KMime::Message::Ptr message = composer->resultMessages().constFirst();
0254     delete composer;
0255     composer = nullptr;
0256 
0257     // setup a viewer
0258     ComposerViewBase view(this, nullptr);
0259     AttachmentModel model(this);
0260     AttachmentControllerBase controller(&model, nullptr, nullptr);
0261     MessageComposer::RichTextComposerNg editor;
0262     view.setAttachmentModel(&model);
0263     view.setAttachmentController(&controller);
0264     view.setEditor(&editor);
0265 
0266     // Let's load the email to the viewer
0267     view.setMessage(message, true);
0268 
0269     // QModelIndex index = model.index(0, 0);
0270     QCOMPARE(editor.toPlainText(), data);
0271     QCOMPARE(model.rowCount(), 2);
0272     AttachmentPart::Ptr part = model.attachments()[0];
0273     QCOMPARE(part->fileName(), fileName);
0274     QCOMPARE(part->data(), fileData);
0275     part = model.attachments()[1];
0276     QCOMPARE(part->fileName(), fileName2);
0277     QCOMPARE(part->data(), fileData2);
0278 }
0279 
0280 void CryptoComposerTest::testSignEncryptLateAttachments_data()
0281 {
0282     QTest::addColumn<int>("format");
0283 
0284     QTest::newRow("OpenPGPMime") << (int)Kleo::OpenPGPMIMEFormat;
0285     QTest::newRow("InlineOpenPGP") << (int)Kleo::InlineOpenPGPFormat;
0286 }
0287 
0288 void CryptoComposerTest::testSignEncryptLateAttachments()
0289 {
0290     QFETCH(int, format);
0291     auto composer = new Composer;
0292     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0293     fillComposerData(composer, data);
0294     fillComposerCryptoData(composer);
0295 
0296     AttachmentPart::Ptr attachment = AttachmentPart::Ptr(new AttachmentPart);
0297     attachment->setData("abc");
0298     attachment->setMimeType("x-some/x-type");
0299     attachment->setFileName(QString::fromLocal8Bit("anattachment.txt"));
0300     attachment->setEncrypted(false);
0301     attachment->setSigned(false);
0302     composer->addAttachmentPart(attachment);
0303 
0304     composer->setSignAndEncrypt(true, true);
0305     composer->setMessageCryptoFormat((Kleo::CryptoMessageFormat)format);
0306 
0307     VERIFYEXEC(composer);
0308     QCOMPARE(composer->resultMessages().size(), 1);
0309 
0310     KMime::Message::Ptr message = composer->resultMessages().constFirst();
0311     delete composer;
0312     composer = nullptr;
0313 
0314     // as we have an additional attachment, just ignore it when checking for sign/encrypt
0315     KMime::Content *b = MessageCore::NodeHelper::firstChild(message.data());
0316     ComposerTestUtil::verifySignatureAndEncryption(b, data.toUtf8(), (Kleo::CryptoMessageFormat)format, true);
0317 
0318     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0319     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0320 
0321     // now check the attachment separately
0322     QCOMPARE(QString::fromLatin1(MessageCore::NodeHelper::nextSibling(b)->body()), QString::fromLatin1("abc"));
0323 }
0324 
0325 // protected headers
0326 void CryptoComposerTest::testProtectedHeaders_data()
0327 {
0328     QTest::addColumn<QString>("data");
0329     QTest::addColumn<bool>("sign");
0330     QTest::addColumn<bool>("encrypt");
0331     QTest::addColumn<Headers::contentEncoding>("cte");
0332 
0333     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0334     QTest::newRow("SignOpenPGPMime") << data << true << false << Headers::CE7Bit;
0335     QTest::newRow("EncryptOpenPGPMime") << data << false << true << Headers::CE7Bit;
0336     QTest::newRow("SignEncryptOpenPGPMime") << data << true << true << Headers::CE7Bit;
0337 }
0338 
0339 void CryptoComposerTest::testProtectedHeaders()
0340 {
0341     QFETCH(QString, data);
0342     QFETCH(bool, sign);
0343     QFETCH(bool, encrypt);
0344     QFETCH(Headers::contentEncoding, cte);
0345 
0346     auto composer = new Composer;
0347 
0348     fillComposerData(composer, data);
0349     fillComposerCryptoData(composer);
0350 
0351     composer->setSignAndEncrypt(sign, encrypt);
0352     composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0353 
0354     VERIFYEXEC(composer);
0355     QCOMPARE(composer->resultMessages().size(), 1);
0356 
0357     KMime::Message::Ptr message = composer->resultMessages().first();
0358 
0359     // parse the result and make sure it is valid in various ways
0360     MimeTreeParser::SimpleObjectTreeSource testSource;
0361     MimeTreeParser::NodeHelper nh;
0362     MimeTreeParser::ObjectTreeParser otp(&testSource, &nh);
0363 
0364     testSource.setDecryptMessage(true);
0365     otp.parseObjectTree(message.data());
0366 
0367     if (encrypt) {
0368         QCOMPARE(nh.encryptionState(message.data()), MimeTreeParser::KMMsgFullyEncrypted);
0369     }
0370 
0371     if (sign && !encrypt) {
0372         QCOMPARE(nh.signatureState(message.data()), MimeTreeParser::KMMsgFullySigned);
0373     }
0374 
0375     KMime::Content *part = nullptr;
0376 
0377     if (sign && !encrypt) {
0378         part = Util::findTypeInMessage(message.data(), "text", "plain");
0379     } else if (encrypt) {
0380         auto extraContents = nh.extraContents(message.data());
0381         QCOMPARE(extraContents.size(), 1);
0382         part = extraContents.first();
0383         if (sign) {
0384             QVERIFY(!part->contentType(false)->hasParameter(QStringLiteral("protected-headers")));
0385             QVERIFY(!part->headerByType("to"));
0386             QVERIFY(!part->headerByType("from:"));
0387             part = Util::findTypeInMessage(part, "text", "plain");
0388         }
0389     }
0390     QVERIFY(part);
0391     QCOMPARE(part->contentType(false)->parameter(QStringLiteral("protected-headers")), QStringLiteral("v1"));
0392     QCOMPARE(part->headerByType("to")->asUnicodeString(), QStringLiteral("you@you.you"));
0393     QCOMPARE(part->headerByType("from")->asUnicodeString(), QStringLiteral("me@me.me"));
0394 }
0395 
0396 void CryptoComposerTest::testBCCEncrypt_data()
0397 {
0398     QTest::addColumn<int>("format");
0399 
0400     QTest::newRow("OpenPGPMime") << (int)Kleo::OpenPGPMIMEFormat;
0401     QTest::newRow("InlineOpenPGP") << (int)Kleo::InlineOpenPGPFormat;
0402 }
0403 
0404 // secondary recipients
0405 
0406 void CryptoComposerTest::testBCCEncrypt()
0407 {
0408     QFETCH(int, format);
0409     auto composer = new Composer;
0410     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0411     fillComposerData(composer, data);
0412     composer->infoPart()->setBcc(QStringList(QStringLiteral("bcc@bcc.org")));
0413 
0414     std::vector<GpgME::Key> keys = MessageComposer::Test::getKeys();
0415 
0416     QStringList primRecipients;
0417     primRecipients << QString::fromLocal8Bit("you@you.you");
0418     std::vector<GpgME::Key> pkeys;
0419     pkeys.push_back(keys[1]);
0420 
0421     QStringList secondRecipients;
0422     secondRecipients << QString::fromLocal8Bit("bcc@bcc.org");
0423     std::vector<GpgME::Key> skeys;
0424     skeys.push_back(keys[2]);
0425 
0426     QList<QPair<QStringList, std::vector<GpgME::Key>>> encKeys;
0427     encKeys.append(QPair<QStringList, std::vector<GpgME::Key>>(primRecipients, pkeys));
0428     encKeys.append(QPair<QStringList, std::vector<GpgME::Key>>(secondRecipients, skeys));
0429 
0430     composer->setSignAndEncrypt(true, true);
0431     composer->setMessageCryptoFormat((Kleo::CryptoMessageFormat)format);
0432 
0433     composer->setEncryptionKeys(encKeys);
0434     composer->setSigningKeys(keys);
0435 
0436     VERIFYEXEC(composer);
0437     QCOMPARE(composer->resultMessages().size(), 2);
0438 
0439     KMime::Message::Ptr primMessage = composer->resultMessages().constFirst();
0440     KMime::Message::Ptr secMessage = composer->resultMessages()[1];
0441     delete composer;
0442     composer = nullptr;
0443 
0444     ComposerTestUtil::verifySignatureAndEncryption(primMessage.data(), data.toUtf8(), (Kleo::CryptoMessageFormat)format);
0445 
0446     QCOMPARE(primMessage->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0447     QCOMPARE(primMessage->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0448 
0449     ComposerTestUtil::verifySignatureAndEncryption(secMessage.data(), data.toUtf8(), (Kleo::CryptoMessageFormat)format);
0450 
0451     QCOMPARE(secMessage->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0452     QCOMPARE(secMessage->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0453 }
0454 
0455 // inline pgp
0456 void CryptoComposerTest::testOpenPGPInline_data()
0457 {
0458     QTest::addColumn<QString>("data");
0459     QTest::addColumn<bool>("sign");
0460     QTest::addColumn<bool>("encrypt");
0461     QTest::addColumn<Headers::contentEncoding>("cte");
0462 
0463     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0464     QTest::newRow("SignOpenPGPInline") << data << true << false << Headers::CE7Bit;
0465     QTest::newRow("EncryptOpenPGPInline") << data << false << true << Headers::CE7Bit;
0466     QTest::newRow("SignEncryptOpenPGPInline") << data << true << true << Headers::CE7Bit;
0467 }
0468 
0469 void CryptoComposerTest::testOpenPGPInline()
0470 {
0471     QFETCH(QString, data);
0472     QFETCH(bool, sign);
0473     QFETCH(bool, encrypt);
0474     QFETCH(Headers::contentEncoding, cte);
0475 
0476     auto composer = new Composer;
0477 
0478     fillComposerData(composer, data);
0479     fillComposerCryptoData(composer);
0480 
0481     composer->setSignAndEncrypt(sign, encrypt);
0482     composer->setMessageCryptoFormat(Kleo::InlineOpenPGPFormat);
0483 
0484     VERIFYEXEC(composer);
0485     QCOMPARE(composer->resultMessages().size(), 1);
0486 
0487     KMime::Message::Ptr message = composer->resultMessages().constFirst();
0488     delete composer;
0489     composer = nullptr;
0490 
0491     if (sign && !encrypt) {
0492         data += QLatin1Char('\n');
0493     }
0494     // qDebug() << "message:" << message->encodedContent();
0495     ComposerTestUtil::verify(sign, encrypt, message.data(), data.toUtf8(), Kleo::InlineOpenPGPFormat, cte);
0496 
0497     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0498     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0499 }
0500 
0501 // s-mime
0502 
0503 void CryptoComposerTest::testSMIME_data()
0504 {
0505     QTest::addColumn<QString>("data");
0506     QTest::addColumn<bool>("sign");
0507     QTest::addColumn<bool>("encrypt");
0508     QTest::addColumn<Headers::contentEncoding>("cte");
0509 
0510     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0511     QTest::newRow("SignSMIME") << data << true << false << Headers::CE7Bit;
0512     QTest::newRow("EncryptSMIME") << data << false << true << Headers::CE7Bit;
0513     QTest::newRow("SignEncryptSMIME") << data << true << true << Headers::CE7Bit;
0514 }
0515 
0516 void CryptoComposerTest::testSMIME()
0517 {
0518     QFETCH(bool, sign);
0519     QFETCH(bool, encrypt);
0520 
0521     runSMIMETest(sign, encrypt, false);
0522 }
0523 
0524 void CryptoComposerTest::testSMIMEOpaque_data()
0525 {
0526     QTest::addColumn<QString>("data");
0527     QTest::addColumn<bool>("sign");
0528     QTest::addColumn<bool>("encrypt");
0529     QTest::addColumn<Headers::contentEncoding>("cte");
0530 
0531     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0532     QTest::newRow("SignSMIMEOpaque") << data << true << false << Headers::CE7Bit;
0533     QTest::newRow("EncryptSMIMEOpaque") << data << false << true << Headers::CE7Bit;
0534     QTest::newRow("SignEncryptSMIMEOpaque") << data << true << true << Headers::CE7Bit;
0535 }
0536 
0537 void CryptoComposerTest::testSMIMEOpaque()
0538 {
0539     QFETCH(bool, sign);
0540     QFETCH(bool, encrypt);
0541 
0542     runSMIMETest(sign, encrypt, true);
0543 }
0544 
0545 // contentTransferEncoding
0546 
0547 void CryptoComposerTest::testCTEquPr_data()
0548 {
0549     QTest::addColumn<QString>("data");
0550     QTest::addColumn<bool>("sign");
0551     QTest::addColumn<bool>("encrypt");
0552     QTest::addColumn<Headers::contentEncoding>("cte");
0553 
0554     QString data(QString::fromLatin1("All happy families are alike; each unhappy family is unhappy in its own way. [ä]"));
0555     QTest::newRow("CTEquPr:Sign") << data << true << false << Headers::CEquPr;
0556     QTest::newRow("CTEquPr:Encrypt") << data << false << true << Headers::CE7Bit;
0557     QTest::newRow("CTEquPr:SignEncrypt") << data << true << true << Headers::CE7Bit;
0558 
0559     data = QStringLiteral(
0560         "All happy families are alike;\n\n\n\neach unhappy family is unhappy in its own way.\n--\n hallloasdfasdfsadfsdf asdf sadfasdf sdf sdf sdf sadfasdf "
0561         "sdaf daf sdf asdf sadf asdf asdf [ä]");
0562     QTest::newRow("CTEquPr:Sign:Newline") << data << true << false << Headers::CEquPr;
0563     QTest::newRow("CTEquPr:Encrypt:Newline") << data << false << true << Headers::CE7Bit;
0564     QTest::newRow("CTEquPr:SignEncrypt:Newline") << data << true << true << Headers::CE7Bit;
0565 }
0566 
0567 void CryptoComposerTest::testCTEquPr()
0568 {
0569     testSMIME();
0570     testSMIMEOpaque();
0571     testOpenPGPMime();
0572     testOpenPGPInline();
0573 }
0574 
0575 void CryptoComposerTest::testCTEbase64_data()
0576 {
0577     QTest::addColumn<QString>("data");
0578     QTest::addColumn<bool>("sign");
0579     QTest::addColumn<bool>("encrypt");
0580     QTest::addColumn<Headers::contentEncoding>("cte");
0581 
0582     QString data(
0583         QStringLiteral("[ääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääää"
0584                        "äääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääääää"
0585                        "äääääääääääääääääääääääääääääääääääääääääääääää]"));
0586     QTest::newRow("CTEbase64:Sign") << data << true << false << Headers::CEbase64;
0587     QTest::newRow("CTEbase64:Encrypt") << data << false << true << Headers::CE7Bit;
0588     QTest::newRow("CTEbase64:SignEncrypt") << data << true << true << Headers::CE7Bit;
0589 }
0590 
0591 void CryptoComposerTest::testCTEbase64()
0592 {
0593     testSMIME();
0594     testSMIMEOpaque();
0595     testOpenPGPMime();
0596     testOpenPGPInline();
0597 }
0598 
0599 void CryptoComposerTest::testSetGnupgHome_data()
0600 {
0601     QTest::addColumn<QString>("data");
0602     QTest::addColumn<bool>("sign");
0603 
0604     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0605 
0606     QTest::newRow("sign") << data << true;
0607     QTest::newRow("notsign") << data << false;
0608 }
0609 
0610 void CryptoComposerTest::testSetGnupgHome()
0611 {
0612     QFETCH(QString, data);
0613     QFETCH(bool, sign);
0614 
0615     bool encrypt(true);
0616 
0617     KMime::Message::Ptr message;
0618     QTemporaryDir dir;
0619     {
0620         auto composer = new Composer;
0621 
0622         fillComposerData(composer, data);
0623         fillComposerCryptoData(composer);
0624 
0625         composer->setGnupgHome(dir.path());
0626         composer->setSignAndEncrypt(sign, encrypt);
0627         composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0628 
0629         QCOMPARE(composer->exec(), false);
0630     }
0631 
0632     const std::vector<GpgME::Key> &keys = Test::getKeys();
0633     for (const auto &key : keys) {
0634         Test::populateKeyring(dir.path(), key);
0635     }
0636 
0637     {
0638         auto composer = new Composer;
0639 
0640         fillComposerData(composer, data);
0641         fillComposerCryptoData(composer);
0642 
0643         composer->setGnupgHome(dir.path());
0644         composer->setSignAndEncrypt(sign, encrypt);
0645         composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0646 
0647         VERIFYEXEC((composer));
0648         QCOMPARE(composer->resultMessages().size(), 1);
0649 
0650         message = composer->resultMessages().first();
0651     }
0652 
0653     ComposerTestUtil::verify(sign, encrypt, message.data(), data.toUtf8(), Kleo::OpenPGPMIMEFormat, Headers::CE7Bit);
0654 
0655     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0656     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0657 }
0658 
0659 void CryptoComposerTest::testAutocryptHeaders_data()
0660 {
0661     QTest::addColumn<QString>("data");
0662     QTest::addColumn<bool>("encrypt");
0663     QTest::addColumn<bool>("sign");
0664 
0665     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0666 
0667     QTest::newRow("encrypt+sign") << data << true << true;
0668     QTest::newRow("encrypt") << data << true << false;
0669     QTest::newRow("sign") << data << false << true;
0670     QTest::newRow("noencrypt+nosign") << data << false << false;
0671 }
0672 
0673 void CryptoComposerTest::testAutocryptHeaders()
0674 {
0675     QFETCH(QString, data);
0676     QFETCH(bool, encrypt);
0677     QFETCH(bool, sign);
0678 
0679     std::vector<GpgME::Key> keys = Test::getKeys();
0680 
0681     KMime::Message::Ptr message;
0682     QTemporaryDir dir;
0683     {
0684         auto composer = new Composer;
0685 
0686         fillComposerData(composer, data);
0687         fillComposerCryptoData(composer);
0688 
0689         composer->setAutocryptEnabled(true);
0690         composer->setSenderEncryptionKey(keys[0]);
0691         composer->setGnupgHome(dir.path());
0692         composer->setSignAndEncrypt(sign, encrypt);
0693         composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0694 
0695         QCOMPARE(composer->exec(), false);
0696     }
0697 
0698     for (const auto &key : keys) {
0699         Test::populateKeyring(dir.path(), key);
0700     }
0701 
0702     {
0703         auto composer = new Composer;
0704 
0705         fillComposerData(composer, data);
0706         fillComposerCryptoData(composer);
0707 
0708         composer->setAutocryptEnabled(true);
0709         composer->setSenderEncryptionKey(keys[0]);
0710         composer->setGnupgHome(dir.path());
0711         composer->setSignAndEncrypt(sign, encrypt);
0712         composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0713 
0714         VERIFYEXEC((composer));
0715         QCOMPARE(composer->resultMessages().size(), 1);
0716 
0717         message = composer->resultMessages().first();
0718     }
0719 
0720     if (sign || encrypt) {
0721         ComposerTestUtil::verify(sign, encrypt, message.data(), data.toUtf8(), Kleo::OpenPGPMIMEFormat, Headers::CE7Bit);
0722     }
0723 
0724     QVERIFY(message->headerByType("autocrypt"));
0725     QVERIFY(message->headerByType("Autocrypt")
0726                 ->asUnicodeString()
0727                 .startsWith(QStringLiteral("addr=me@me.me; keydata= mQENBEr9ij4BCADaFvyhzV7IrCAr/sCvfoPerAd4dYIGTeCeBmInu3p4oEG0rXTB2zL2t9zd7jV")));
0728     QVERIFY(!message->headerByType("autocrypt-gossip"));
0729     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0730     QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0731 }
0732 
0733 void CryptoComposerTest::testAutocryptGossip_data()
0734 {
0735     QTest::addColumn<QString>("data");
0736     QTest::addColumn<bool>("encrypt");
0737     QTest::addColumn<bool>("sign");
0738     QTest::addColumn<QStringList>("recipients");
0739 
0740     QString data(QStringLiteral("All happy families are alike; each unhappy family is unhappy in its own way."));
0741 
0742     QStringList recipients({QStringLiteral("you@you.you")});
0743 
0744     QTest::newRow("encrypt") << data << true << false << recipients;
0745     QTest::newRow("encrypt+sign") << data << true << true << recipients;
0746     QTest::newRow("sign") << data << false << true << recipients;
0747 
0748     recipients.append(QStringLiteral("leo@kdab.com"));
0749     QTest::newRow("encrypt-multiple") << data << true << false << recipients;
0750     QTest::newRow("encrypt+sign-multiple") << data << true << true << recipients;
0751     QTest::newRow("sign-multiple") << data << false << true << recipients;
0752 }
0753 
0754 void CryptoComposerTest::testAutocryptGossip()
0755 {
0756     QFETCH(QString, data);
0757     QFETCH(bool, encrypt);
0758     QFETCH(bool, sign);
0759     QFETCH(QStringList, recipients);
0760 
0761     std::vector<GpgME::Key> keys = Test::getKeys();
0762 
0763     KMime::Message::Ptr message;
0764 
0765     {
0766         auto composer = new Composer;
0767 
0768         fillComposerData(composer, data);
0769         composer->infoPart()->setTo(recipients);
0770         fillComposerCryptoData(composer);
0771 
0772         if (recipients.size() > 1) {
0773             auto job = QGpgME::openpgp()->keyListJob(false);
0774             std::vector<GpgME::Key> eKeys;
0775             GpgME::KeyListResult res = job->exec(recipients, false, eKeys);
0776 
0777             QVERIFY(!res.error());
0778             QCOMPARE(eKeys.size(), 1);
0779 
0780             eKeys.push_back(keys[0]);
0781             eKeys.push_back(keys[1]);
0782 
0783             QList<QPair<QStringList, std::vector<GpgME::Key>>> encKeys;
0784             encKeys.append({recipients, eKeys});
0785 
0786             composer->setEncryptionKeys(encKeys);
0787         }
0788         composer->setAutocryptEnabled(true);
0789         composer->setSenderEncryptionKey(keys[0]);
0790         composer->setSignAndEncrypt(sign, encrypt);
0791         composer->setMessageCryptoFormat(Kleo::OpenPGPMIMEFormat);
0792 
0793         VERIFYEXEC((composer));
0794         QCOMPARE(composer->resultMessages().size(), 1);
0795 
0796         message = composer->resultMessages().first();
0797     }
0798 
0799     if (sign || encrypt) {
0800         ComposerTestUtil::verify(sign, encrypt, message.data(), data.toUtf8(), Kleo::OpenPGPMIMEFormat, Headers::CE7Bit);
0801     }
0802 
0803     MimeTreeParser::SimpleObjectTreeSource testSource;
0804     MimeTreeParser::NodeHelper nh;
0805     MimeTreeParser::ObjectTreeParser otp(&testSource, &nh);
0806     testSource.setDecryptMessage(true);
0807     otp.parseObjectTree(message.data());
0808 
0809     QVERIFY(!message->headerByType("autocrypt-gossip"));
0810     if (encrypt && recipients.size() > 1) {
0811         QCOMPARE(nh.headers("autocrypt-gossip", message.data()).size(), 2);
0812 
0813         auto headers = QStringList();
0814         for (const auto header : nh.headers("autocrypt-gossip", message.data())) {
0815             headers.append(header->asUnicodeString());
0816         }
0817 
0818         headers.sort();
0819 
0820         QVERIFY(
0821             headers[0].startsWith(QStringLiteral("addr=leo@kdab.com; keydata= mQINBEr4pSwBEADG/B1VaoxT7mnQfwekkY+f8wkqFVLvTwN0W59Ze/pxmuRf/iS0tZjsEiPK0za")));
0822         QVERIFY(
0823             headers[1].startsWith(QStringLiteral("addr=you@you.com; keydata= mI0ESw2YuAEEALakcld4goNkwIL5gMETM3R+zI+AoJcuQWUpvS7AqwyR9/UAkVd3D+r32CgWhFi")));
0824     } else {
0825         QCOMPARE(nh.headers("autocrypt-gossip", message.data()).size(), 0);
0826     }
0827     QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("me@me.me"));
0828     QCOMPARE(message->to()->asUnicodeString(), recipients.join(QStringLiteral(", ")));
0829 }
0830 
0831 // Helper methods
0832 void CryptoComposerTest::fillComposerData(Composer *composer, const QString &data)
0833 {
0834     composer->globalPart()->setFallbackCharsetEnabled(true);
0835     composer->infoPart()->setFrom(QStringLiteral("me@me.me"));
0836     composer->infoPart()->setTo(QStringList(QStringLiteral("you@you.you")));
0837     composer->textPart()->setWrappedPlainText(data);
0838 }
0839 
0840 void CryptoComposerTest::fillComposerCryptoData(Composer *composer)
0841 {
0842     std::vector<GpgME::Key> keys = MessageComposer::Test::getKeys();
0843 
0844     // qDebug() << "got num of keys:" << keys.size();
0845 
0846     QStringList recipients;
0847     recipients << QString::fromLocal8Bit("you@you.you");
0848 
0849     QList<QPair<QStringList, std::vector<GpgME::Key>>> encKeys;
0850     encKeys.append(QPair<QStringList, std::vector<GpgME::Key>>(recipients, keys));
0851 
0852     composer->setEncryptionKeys(encKeys);
0853     composer->setSigningKeys(keys);
0854 }
0855 
0856 void CryptoComposerTest::runSMIMETest(bool sign, bool enc, bool opaque)
0857 {
0858     QFETCH(QString, data);
0859     QFETCH(Headers::contentEncoding, cte);
0860 
0861     auto composer = new Composer;
0862 
0863     fillComposerData(composer, data);
0864     composer->infoPart()->setFrom(QStringLiteral("test@example.com"));
0865 
0866     std::vector<GpgME::Key> keys = MessageComposer::Test::getKeys(true);
0867     QStringList recipients;
0868     recipients << QString::fromLocal8Bit("you@you.you");
0869     QList<QPair<QStringList, std::vector<GpgME::Key>>> encKeys;
0870     encKeys.append(QPair<QStringList, std::vector<GpgME::Key>>(recipients, keys));
0871     composer->setEncryptionKeys(encKeys);
0872     composer->setSigningKeys(keys);
0873     composer->setSignAndEncrypt(sign, enc);
0874     Kleo::CryptoMessageFormat f;
0875     if (opaque) {
0876         f = Kleo::SMIMEOpaqueFormat;
0877     } else {
0878         f = Kleo::SMIMEFormat;
0879     }
0880     composer->setMessageCryptoFormat(f);
0881 
0882     const bool result = composer->exec();
0883     // QEXPECT_FAIL("", "GPG setup problems", Continue);
0884     QVERIFY(result);
0885     if (result) {
0886         QCOMPARE(composer->resultMessages().size(), 1);
0887         KMime::Message::Ptr message = composer->resultMessages().constFirst();
0888         delete composer;
0889         composer = nullptr;
0890 
0891         // qDebug() << "message:" << message->encodedContent();
0892 
0893         ComposerTestUtil::verify(sign, enc, message.data(), data.toUtf8(), f, cte);
0894 
0895         QCOMPARE(message->from()->asUnicodeString(), QString::fromLocal8Bit("test@example.com"));
0896         QCOMPARE(message->to()->asUnicodeString(), QString::fromLocal8Bit("you@you.you"));
0897     }
0898 }
0899 
0900 #include "moc_cryptocomposertest.cpp"