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"