From ab56b25bdd214cfc7d8b6bacc8ac92ec9db19d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Mon, 22 Apr 2019 22:30:57 +0200 Subject: [PATCH 01/12] Distinguish between mMsg and mOrigMsg. Summary: TemplateParser reads from mOrigMsg and writes to mMsg. Let's make it obvious what we read/write. Reviewers: #kde_pim Subscribers: kde-pim Tags: #kde_pim Differential Revision: https://phabricator.kde.org/D20756 --- .../autotests/templateparserjobtest.cpp | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index 770b22f2c..4aba591de 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -192,14 +192,15 @@ void TemplateParserJobTest::test_processWithTemplatesForBody() QFETCH(QString, selection); KMime::Message::Ptr msg(new KMime::Message()); - msg->setBody(text.toLocal8Bit()); - msg->parse(); + KMime::Message::Ptr origMsg(new KMime::Message()); + origMsg->setBody(text.toLocal8Bit()); + origMsg->parse(); TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Reply); parser->setSelection(selection); KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; parser->setIdentityManager(identMan); parser->setAllowDecryption(true); - parser->d->mOrigMsg = msg; + parser->d->mOrigMsg = origMsg; QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); parser->processWithTemplate(command); @@ -252,7 +253,7 @@ void TemplateParserJobTest::test_processWithTemplatesForContent_data() QTest::newRow("%INSERT") << insertFileNameCommand << fileName << "test insert file!\n" << false; insertFileNameCommand = QStringLiteral("%PUT=\"%1\"").arg(insertFileName); QTest::newRow("%PUT") << insertFileNameCommand << fileName << "test insert file!\n" << false; - QTest::newRow("%MSGID") << "%MSGID" << fileName << "<20150@foo.kde.org>" << false; + QTest::newRow("%OMSGID") << "%OMSGID" << fileName << "<20150@foo.kde.org>" << false; QTest::newRow("%SYSTEM") << "%SYSTEM=\"echo foo\"" << fileName << "foo\n" << false; QTest::newRow("%DEBUG") << "%DEBUG" << fileName << "" << false; QTest::newRow("%DEBUGOFF") << "%DEBUGOFF" << fileName << "" << false; @@ -281,14 +282,15 @@ void TemplateParserJobTest::test_processWithTemplatesForContent() const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); QVERIFY(!mailData.isEmpty()); KMime::Message::Ptr msg(new KMime::Message); - msg->setContent(mailData); - msg->parse(); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Reply); KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; parser->setIdentityManager(identMan); parser->setAllowDecryption(false); - parser->d->mOrigMsg = msg; + parser->d->mOrigMsg = origMsg; QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); parser->processWithTemplate(command); QVERIFY(spy.wait()); @@ -325,14 +327,15 @@ void TemplateParserJobTest::test_processWithTemplatesForContentOtherTimeZone() const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); QVERIFY(!mailData.isEmpty()); KMime::Message::Ptr msg(new KMime::Message); - msg->setContent(mailData); - msg->parse(); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Reply); KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; parser->setIdentityManager(identMan); parser->setAllowDecryption(false); - parser->d->mOrigMsg = msg; + parser->d->mOrigMsg = origMsg; QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); parser->processWithTemplate(command); QVERIFY(spy.wait()); From fa225b1a115d858f3277626e8fc0b580b0a710f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Wed, 24 Apr 2019 00:21:23 +0200 Subject: [PATCH 02/12] MimeTreeParser returns wrong content for inline mesasges with multiple encrypted blocks. --- .../data/openpgp-inline-multiple.mbox | 51 +++++++++++++ .../data/openpgp-inline-multiple.mbox.html | 72 +++++++++++++++++++ .../data/openpgp-inline-multiple.mbox.tree | 7 ++ 3 files changed, 130 insertions(+) create mode 100644 mimetreeparser/autotests/data/openpgp-inline-multiple.mbox create mode 100644 mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.html create mode 100644 mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.tree diff --git a/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox new file mode 100644 index 000000000..e42eccd76 --- /dev/null +++ b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox @@ -0,0 +1,51 @@ +Subject: Testcase 'reply-decrytion-oracle' (PGP INLINE) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: text/plain + +Please reply to this message +. +. +. + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf7BxmM0vO8nG37hKqoqOHb35JqprJM+sqF7JFmrsuWe6V2 +PAyyE2wdtq+AhvXjVnggxYLwU+DEFpBTmWr1rsanyV8hWXRbecfN/9gN/4/N9y7Z +XSx2OeE/uA5z8Kz5vrv/ywMqcVHjB5MQPTcLC2Zlg8MVltpriy6mdAkON4I3t7kl +j9uwQRY7HeKvsib63HWnYAOV/fYPXXor/lioeYIll08uuCiTh3Z9fEhXQI/az5Ft +e/xa70xGqviux+OvhoNUSZspzl7vK7e/NTBlC+LF1zVXUXT8prrd+ZFNwKvtn0Hl +W4KfNqTM9TJB8vpE5FWnH6+B365ZvxZopZ5F/9szp9JGAUCNdX5WujBreg7nTLui +UrnDNwOvjvsE/gsoO3n3jARK+Tu8PfUl8V1bHiCeGJz/mkA9uGJ/IApcT4rYsoHB +nVQjW1NJ6A== +=zrF/ +-----END PGP MESSAGE----- + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MCqjMjAB80hAMAHfa7bdk/6L4DJQBQn+zHRv6oYzzYFC +8l79DDIE2uorQNFj1ZBw5+pi7+/2QmAANnG2ug5W0HRphg2WPXTUswy5H+mg08PM +MXRsP9lX5pAXEbLZVp61tvOQHnO/ltBhHHBwRaIq2tiirUUhy5erqLwlkSyN8xHM +Bh0u/dIJw7ewMk0l3BtF/GuP7l6PtUxT7P0Vwit4h1FV1bc9mSFmBNN16dvixJ4l +jK0mYEqT97SNZpg0MPOxx8E3xuJptzea4qmACv5zx4gYHlZRM0ZlKNqffmRauWOe +pDCjZv2F1IUJOg28NzZhKCBVhmhBmP1VmLNYFKGAsNJHAV+3uN2YYWzbhoOJAE0N +UxLI0EQN4y7OkAnGiRH45HygLxAjTk6dPiP5OD9OhUnSqofAjajlmqzfAAVMxY1a +epnRKPsnCZU= +=dqBN +-----END PGP MESSAGE----- + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MNDSEBVsF78knI+uirDbLSLrHicrXExTocmXr2DZOggI +zMYCAHyg7ohINA40/8ZuR0bC9h6qCZjjhR+VFe2edRFshXlbuzykjpXNYcSv61Sm +9TAVpgAExzS5VhAxYIJ6+zWJR8+hgv63oREZPWlJ23utBDAMkEeY7cga3wn1HZMZ +g4XQZ94a8s9s/I+s3dLOdHGdxw+hmSnxjMhI6TMcZV/Kvr1MkkW10N0h0+hiuq2O +4owEztpm4See8fCkRfhr0TO+a8ElCtIXjVwqeB0tQh0fU3QaaNiDXYawoFMQXG8N +nwCP92glfOeAvJn9KuLwO3ee+WKwcrJhsFRMmjziDdJGAUvptVDNrk2P/0fzo/Xl +ypmw8zhir6ch+4C2+5yFCtVSmC+3Y7+NQ4YE4AR/z5rGvA1lxclulU1DSGkhFTbJ +XEVyg8o23A== +=Bs3d +-----END PGP MESSAGE----- + +whoo three encrypted parts inside. diff --git a/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.html b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.html new file mode 100644 index 000000000..8b602a22b --- /dev/null +++ b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.html @@ -0,0 +1,72 @@ + + + + +
+ +
+
+
Please reply to this message
+
.
+
.
+
.
+
+
+ + + + + + + + + + +
+
Encrypted messageShow Details
+
+
+
first part
+
+
End of encrypted message
+ + + + + + + + + + +
+
Encrypted messageShow Details
+
+
+
second part
+
+
End of encrypted message
+ + + + + + + + + + +
+
Encrypted messageShow Details
+
+
+
third part
+
+
End of encrypted message
+
+
whoo three encrypted parts inside.
+
+
+
+ + diff --git a/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.tree b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.tree new file mode 100644 index 000000000..bbf0edfc1 --- /dev/null +++ b/mimetreeparser/autotests/data/openpgp-inline-multiple.mbox.tree @@ -0,0 +1,7 @@ + * MimeTreeParser::MessagePartList + * MimeTreeParser::TextMessagePart + * MimeTreeParser::MessagePart + * MimeTreeParser::EncryptedMessagePart + * MimeTreeParser::EncryptedMessagePart + * MimeTreeParser::EncryptedMessagePart + * MimeTreeParser::MessagePart From d397aa46e809203c94e31891caac57affac746d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Mon, 22 Apr 2019 22:41:13 +0200 Subject: [PATCH 03/12] Test mails for Decryption Oracle based on replying to PGP or S/MIME. Summary: In order to make sure we never add a Decryption Oracle add test mails to TemplateParser. BUG: 404698 Reviewers: #kde_pim, aacid, dfaure Subscribers: kde-pim Tags: #kde_pim Differential Revision: https://phabricator.kde.org/D20757 --- templateparser/autotests/data/404698-gpg.mbox | 120 ++++++++++++++++++ .../data/404698-gpg.mbox.plain.reply | 51 ++++++++ .../autotests/data/404698-smime.mbox | 88 +++++++++++++ .../data/404698-smime.mbox.plain.reply | 51 ++++++++ 4 files changed, 310 insertions(+) create mode 100644 templateparser/autotests/data/404698-gpg.mbox create mode 100644 templateparser/autotests/data/404698-gpg.mbox.plain.reply create mode 100644 templateparser/autotests/data/404698-smime.mbox create mode 100644 templateparser/autotests/data/404698-smime.mbox.plain.reply diff --git a/templateparser/autotests/data/404698-gpg.mbox b/templateparser/autotests/data/404698-gpg.mbox new file mode 100644 index 000000000..ed9c0f98c --- /dev/null +++ b/templateparser/autotests/data/404698-gpg.mbox @@ -0,0 +1,120 @@ +Subject: Testcase 'reply-mix-crlf' (PGP/MIME) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain + +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. + +--BOUNDARY +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="DELIMITER" + +--DELIMITER +Content-Type: application/pgp-encrypted + +Version: 1 + +--DELIMITER +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1 + +hIwDGJlthTT7oq0BA/9NtLLXbiIJVS6pOynwEeSznrQK7kYVla8RM43//JECCkGJ +azEaSBznabBv6epaFmQtVHLMXlCbZnMmW9loyqPBfMoAms6kKKBdG/jqhus89iXE ++seXngC233Va/gZMb2DxOqIokVNfj9tpR7xQ8wS/jHTDiLNc1GOQC7ku42z2bNLA +IQFRD/qbBFz89hU4wP4cYoAysOnEDojFrsrnCidTHJOJrndM6PPUtH/jQCyfr/EG +2tSpJwYKvmT6ly3yqaGLBtRPIxiv+dMe+7yw0t40qbjvvaTGavErEBJEKX5eWbTN +/sjajHpUHqs6SIiMheH9dr+WfzFONtVbPEgGRmOERhlgTl/nLo86AZpjJroIGKJJ +tTHCcoQGAWG+N7wrCE1RxR0kkMs4nRozj0TLu6ZyXMs+H063MewTPNxNAiQT1Nbi +udKWmfLBlxn06p+JDzUKxj8PFwObdbxTvACzbAvBY1aHMQ== +=mLl3 +-----END PGP MESSAGE----- + + +--DELIMITER-- + +--BOUNDARY + +--BOUNDARY +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="DELIMITER" + +--DELIMITER +Content-Type: application/pgp-encrypted + +Version: 1 + +--DELIMITER +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- +Version: GnuPG v2.0.15 (GNU/Linux) + +hQEMAwzOQ1qnzNo7AQgAtWfDWWI2JUGuptpackiIxpWViEEpGAeruETubiIPwxNb +DNmXrMDhbm/zIbPntIGWJDgUMfABZCUgmlJLWhsceDTt+tXnWGha2VYrN2/WsF6/ +Pqs/TavTvMIJQHDaIH5yDDCaMoq/mGSbcu7go2H8Sw7aBEYlM8jGlqc1HziXnZ1q +3vDiA+4qWfvbNoSRo1kb9Pcq997yg6WqZXH2hJ7cp+hIQ4uTP1/+qgYHMvfPlzQk +XcDguGbIer88ELhuR5622unGBAB4dqp+5w6n9c6rrCH81qhV4W0nqSEvj1tBj78S +ZTi6VBAo5eS0e3iOJqMpwUZz6hQUpJw2wnNRGvLgI9KZAag0HkgPdMeANowg7vpE +L4nU7B0ybhswA2Y7QT/wwCDZu9N1JGeBmy0dgy4sA38Ki27rn2/lIaP0j14JycwM +RTJ1uwI+ZuQiwXlyYtdFZJWe8nraWARch0oKqhaR7aSsxGWo63eiGEQhkQCBFBb3 +Vg0nNCZRBauEqIESEW5EV2zrJqdfNYcz+f9IP125dnQEKgLZ6FxTt3+v +=mhNl +-----END PGP MESSAGE----- + +--DELIMITER-- diff --git a/templateparser/autotests/data/404698-gpg.mbox.plain.reply b/templateparser/autotests/data/404698-gpg.mbox.plain.reply new file mode 100644 index 000000000..580c8fdef --- /dev/null +++ b/templateparser/autotests/data/404698-gpg.mbox.plain.reply @@ -0,0 +1,51 @@ +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. diff --git a/templateparser/autotests/data/404698-smime.mbox b/templateparser/autotests/data/404698-smime.mbox new file mode 100644 index 000000000..7cd5a1060 --- /dev/null +++ b/templateparser/autotests/data/404698-smime.mbox @@ -0,0 +1,88 @@ +Subject: Testcase 'reply-mix-crlf' (S/MIME) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain + +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. + +--BOUNDARY +Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgfwwgfkCAQAwYjBVMQswCQYDVQQGEwJVUzENMAsGA1UECgwE +S0RBQjEWMBQGA1UEAwwNdW5pdHRlc3QgY2VydDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl +LmNvbQIJANNFIDoYY4XJMA0GCSqGSIb3DQEBAQUABIGAJwmmaOeidXUHSQGOf2OBIsPYafVqdORe +y54pEXbXiAfSVUWgI4a9CsiWwcDX8vlaX9ZLLr+L2VmOfr6Yc5214yxzausZVvnUFjy6LUXotuEX +tSar4EW7XI9DjaZc1l985naMsTx9JUa5GyQ9J6PGqhosAKpKMGgKkFAHaOwE1/IwgAYJKoZIhvcN +AQcBMBQGCCqGSIb3DQMHBAieDfmz3WGbN6CABHgEpsLrNn0PAZTDUfNomDypvSCl5bQH+9cKm80m +upMV2r8RBiXS7OaP4SpCxq18afDTTPatvboHIoEX92taTbq8soiAgEs6raSGtEYZNvFL0IYqm7MA +o5HCOmjiEcInyPf14lL3HnPk10FaP3hh58qTHUh4LPYtL7UECOZELYnUfUVhAAAAAAAAAAAAAA== + +--BOUNDARY +Content-Type: application/pkcs7-mime; name="smime.p7m"; smime-type=enveloped-data +Content-Transfer-Encoding: base64 + +MIAGCSqGSIb3DQEHA6CAMIACAQAxgfwwgfkCAQAwYjBVMQswCQYDVQQGEwJVUzENMAsGA1UECgwE +S0RBQjEWMBQGA1UEAwwNdW5pdHRlc3QgY2VydDEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxl +LmNvbQIJANNFIDoYY4XJMA0GCSqGSIb3DQEBAQUABIGAJwmmaOeidXUHSQGOf2OBIsPYafVqdORe +y54pEXbXiAfSVUWgI4a9CsiWwcDX8vlaX9ZLLr+L2VmOfr6Yc5214yxzausZVvnUFjy6LUXotuEX +tSar4EW7XI9DjaZc1l985naMsTx9JUa5GyQ9J6PGqhosAKpKMGgKkFAHaOwE1/IwgAYJKoZIhvcN +AQcBMBQGCCqGSIb3DQMHBAieDfmz3WGbN6CABHgEpsLrNn0PAZTDUfNomDypvSCl5bQH+9cKm80m +upMV2r8RBiXS7OaP4SpCxq18afDTTPatvboHIoEX92taTbq8soiAgEs6raSGtEYZNvFL0IYqm7MA +o5HCOmjiEcInyPf14lL3HnPk10FaP3hh58qTHUh4LPYtL7UECOZELYnUfUVhAAAAAAAAAAAAAA== + +--BOUNDARY-- diff --git a/templateparser/autotests/data/404698-smime.mbox.plain.reply b/templateparser/autotests/data/404698-smime.mbox.plain.reply new file mode 100644 index 000000000..580c8fdef --- /dev/null +++ b/templateparser/autotests/data/404698-smime.mbox.plain.reply @@ -0,0 +1,51 @@ +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. From 9f77a5fdab234bf48744ef843ba01992ee935618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Tue, 23 Apr 2019 17:20:19 +0200 Subject: [PATCH 04/12] Add test for a normal encrypted message, to make sure decrpytion works. --- .../autotests/data/openpgp-encrypted.mbox | 35 +++++++++++++++++++ .../data/openpgp-encrypted.mbox.plain.reply | 1 + 2 files changed, 36 insertions(+) create mode 100644 templateparser/autotests/data/openpgp-encrypted.mbox create mode 100644 templateparser/autotests/data/openpgp-encrypted.mbox.plain.reply diff --git a/templateparser/autotests/data/openpgp-encrypted.mbox b/templateparser/autotests/data/openpgp-encrypted.mbox new file mode 100644 index 000000000..54fe6530f --- /dev/null +++ b/templateparser/autotests/data/openpgp-encrypted.mbox @@ -0,0 +1,35 @@ +From test@kolab.org Wed, 08 Sep 2010 17:02:52 +0200 +From: OpenPGP Test +To: test@kolab.org +Subject: OpenPGP encrypted +Date: Wed, 08 Sep 2010 17:02:52 +0200 +User-Agent: KMail/4.6 pre (Linux/2.6.34-rc2-2-default; KDE/4.5.60; x86_64; ; ) +MIME-Version: 1.0 +Content-Type: multipart/encrypted; boundary="nextPart1357031.ppLHckZtsp"; protocol="application/pgp-encrypted" +Content-Transfer-Encoding: 7Bit + + +--nextPart1357031.ppLHckZtsp +Content-Type: application/pgp-encrypted +Content-Disposition: attachment + +Version: 1 +--nextPart1357031.ppLHckZtsp +Content-Type: application/octet-stream +Content-Disposition: inline; filename="msg.asc" + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf/dJ5Pn6aE02/ImggNDDJBfvRU7vWF3OeKaGNrZd9sWp3Q +x8Tas0r+Yfaoo5cNqEJ7LXaRA9UGJ3BtDEtzLl/xrY++QyewrRtLlfSLXFSifZOA +9eBYmL4cj4Fbp4HR8iUBC2p64FzARQBe4hCyEoIIQPK7+3XqgsFdCIqmnEt1+Nys +mKXN4VSukAcTzjR8JasPKZ+Qayx9+DBu7wJJNzjlhnrIv4AMYOTetLwL7f5/c2j+ +zX/2/9ptWwcBDxMl6WKTpPF4Zf57MgeV3TI4O5FHXfhjldUh6JiSt3i+t4ev9F8A +s1pYZ15qDRwNwshZ7fujJvd1lk7ZDZdAQyKXgHNo0NKOATJ6IN0S5yvFi9FhyHM6 +sGzHXVqBgJspKqOuuoSPuX0RBvAskNPa4yERla0725n/F9AHsbiw4olQvIbKD70+ +gPd1k+MR6OfsGb+m5IIMBSjaKDLtgO9H0JLIq2U7Qf3YU+VsvvPH+PhTnUuz5/Ea +0W1dTWWU0MRh0Z8uKM9KJHjMjkNzBvO4T8uTfRwBPA== +=G9lS +-----END PGP MESSAGE----- + +--nextPart1357031.ppLHckZtsp-- diff --git a/templateparser/autotests/data/openpgp-encrypted.mbox.plain.reply b/templateparser/autotests/data/openpgp-encrypted.mbox.plain.reply new file mode 100644 index 000000000..965dc9a59 --- /dev/null +++ b/templateparser/autotests/data/openpgp-encrypted.mbox.plain.reply @@ -0,0 +1 @@ +encrypted text From ab3c3a0de8691e656423afb5c184d0c8b5c8e4d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Tue, 23 Apr 2019 17:21:29 +0200 Subject: [PATCH 05/12] templateparserjobtest: HTML mime parts are handled differently Make sure that also HTML encrypted messages are not leaked into reply/forward. --- .../autotests/data/404698-gpg-html.mbox | 131 ++++++++++++++++++ .../data/404698-gpg-html.mbox.plain.reply | 51 +++++++ 2 files changed, 182 insertions(+) create mode 100644 templateparser/autotests/data/404698-gpg-html.mbox create mode 100644 templateparser/autotests/data/404698-gpg-html.mbox.plain.reply diff --git a/templateparser/autotests/data/404698-gpg-html.mbox b/templateparser/autotests/data/404698-gpg-html.mbox new file mode 100644 index 000000000..c1a53c266 --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-html.mbox @@ -0,0 +1,131 @@ +Subject: Testcase 'reply-mix-crlf' (PGP/MIME HTML) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain + +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. + +--BOUNDARY +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="DELIMITER" + +--DELIMITER +Content-Type: application/pgp-encrypted + +Version: 1 + +--DELIMITER +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- + +hQELAwzOQ1qnzNo7AQf3Zp/i09urv4DVCcbCu75LQqVtkanqYIaVF+CgUX2aeReD +VIf6Q58I5lX0+ZighYMjoqFyLoIg8KfazaiCZ7prwTOjTUxgVIaEUt46E/zaIU64 +y0M09xrD0ZXvdCb2DPbzBI2YGCUOg+WRN0Bjv90DXgqXLDzdHqJ4w/iFTF3sXTW0 +nxAeOqNWwr4vSOG2AfTbIHpAspl2woqnoKds0dxA8DgGD9ffGx1/VL9aoNPuhdGf +GWko1NfHnwgTaLEBr5Yr5uaDfPvtMfIdtw6HVc5xZfmlPfES9NeL0aHmHe9htuFf +fyEHzFHJDxqny5/PqULxcxBpKJH2jQuGWtzswOj/0sD4ASnTPJ/AmGqI2pWT1KIS +m1mSw7VBTK/f47EeQhdWIbIVt6+oqfjum+aAkwEEOGcUHNcNwclKYlHT1hUesNr5 +mj0XpKVUz1WBRI0O5Vedt7xNJOUIhBSOeiDrZ3dhn8kD12aJvP0NUx88jeR87U3k +F5UvDfsWyjqN4GMzjVV3vLsGShR+8C7I2+DPebyoLUfkqeEUUJOwYg4YL+gjAVHR +VKNvQIQWC5PFMm5LasDF0UdfTtKI+kWYgGTWVKQawr3nBJmly2b2By9biUh2Z4Ly +pUHqKpHEKW5O+VLd0dgzYV9x5Wq7zkKKX44B55W050bh3u9iztfZvghd16Cy7OYB +9h20ZMKFffkZCorrhiN6mHr1YkPXI30ZwC1xkQ6YuUlwIpE5gJr4D14+/zFcJsU0 +grdLbDzFApcwrGrxjiFGMb8tbS6XYyB0uVh0NEX7YGUHYtZnE6JLR0XVYjvSUFGs +plvgdpXbohA3J9T8Grd1M5O7D+SmrXHrZGj8oJW2DST6QmbphlkVBf0LrNK+sqSU +nKxX/pzNqA4Sh/lLJOQ7eON4or2u9JpiP5Zr++Wl99xWBel5iZC9s/8= +=mtFc +-----END PGP MESSAGE----- + + +--DELIMITER-- + +--BOUNDARY + +--BOUNDARY +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="DELIMITER" + +--DELIMITER +Content-Type: application/pgp-encrypted + +Version: 1 + +--DELIMITER +Content-Type: application/octet-stream; name="encrypted.asc" +Content-Disposition: inline; filename="encrypted.asc" + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf9EgAO1PAwK3tquVubNpsRpK6kfvjAVSDXNiUtuMN5G7KG +aqnVl5PmfdLdEbGLjcHyFMsZ8k2alSyG0lFWdXQUqfYE5TSo3en5Zqyc+kK/5pDI +GZ6V5E5I0JPVIeY5lSFIVvSBXCBncK7jdRAtN3WfDL50UQYJX8fAOGc6iiMKDEb8 +jKwJbS0qwjHDwaKKwseE/yuYO3YFUWsijsnxwUXhU0iq3Yv7JIhXKldHFPe+jCOy +v2OQ2064I9mCNi6LjQPcqyXVTESB5/6Sdl1L9/ETjep5Gzlhp8WJTZNIzWJhqmPe +6hebCCJowQ6CxiqVInh46fPfSGw/YuFGRlyWZCSVa9LA+wGb+KaR0oDwHjBsUkhh +VhdNS7kRtx3kec9KaJQHCDFt0aUaMgnFdnNDS3AEQ+5PbplyKYT5PjA1TkhHGXmb +VQ07Xyab3zGPE5DUsUYt/c+bfN3EmaOc8JAZBOJzYw0nL9fSt5E1feo3Ntwse5S1 +yMMK7ALfv6W4/ItWf1KTDCo/A2QiAzZO9Gy8kFOx3nXYeh5BN2Efe5tmdtxgypQP ++b3TJbl98elyS6jiV4xB+gooVTrK3DIJbZi8xcHnBqtg3bSVML5pDJBM1MCcS3cP +eVgJ5JkE1qqiHuk4NFm0KIKMWyjgXUp8XJ7pOpHtu5COEyz3TwpOjmcYUMjQnyQs +/c9DD/oTZZq4y7VTFab9W0iBS0aadHzSR3TQdneIap7MOay79+fZQEqK8zel4qkN +ngaxDyBYA9wy3gsigbb5lBEqX9M8o7VLpz6Hn3CXqxpgaPvE+GFN+r5Os1/bcuSK +EfJTTtPuqx3MjVH9y+wW3fThb5xSoDNgb3Z93HVMGZzcKh9Kt47ZBhxMfb/4N7lE +Hh3qvh6KIJNnVlhm+JqqlVbAUEAg6bFH+CI1RtsCPnrmHjT6ysqeNKciAvVB +=VRca +-----END PGP MESSAGE----- + +--DELIMITER-- diff --git a/templateparser/autotests/data/404698-gpg-html.mbox.plain.reply b/templateparser/autotests/data/404698-gpg-html.mbox.plain.reply new file mode 100644 index 000000000..580c8fdef --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-html.mbox.plain.reply @@ -0,0 +1,51 @@ +Please reply to this message +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. +. From 6173d7fdc198187622ab481cb26fd14dbbd4c700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Tue, 23 Apr 2019 17:22:57 +0200 Subject: [PATCH 06/12] Add test cases for a Decryption Oracle based on PGP inline. --- .../autotests/data/404698-gpg-inline.mbox | 51 +++++++++++++++++++ .../data/404698-gpg-inline.mbox.plain.reply | 5 ++ 2 files changed, 56 insertions(+) create mode 100644 templateparser/autotests/data/404698-gpg-inline.mbox create mode 100644 templateparser/autotests/data/404698-gpg-inline.mbox.plain.reply diff --git a/templateparser/autotests/data/404698-gpg-inline.mbox b/templateparser/autotests/data/404698-gpg-inline.mbox new file mode 100644 index 000000000..e42eccd76 --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-inline.mbox @@ -0,0 +1,51 @@ +Subject: Testcase 'reply-decrytion-oracle' (PGP INLINE) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: text/plain + +Please reply to this message +. +. +. + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf7BxmM0vO8nG37hKqoqOHb35JqprJM+sqF7JFmrsuWe6V2 +PAyyE2wdtq+AhvXjVnggxYLwU+DEFpBTmWr1rsanyV8hWXRbecfN/9gN/4/N9y7Z +XSx2OeE/uA5z8Kz5vrv/ywMqcVHjB5MQPTcLC2Zlg8MVltpriy6mdAkON4I3t7kl +j9uwQRY7HeKvsib63HWnYAOV/fYPXXor/lioeYIll08uuCiTh3Z9fEhXQI/az5Ft +e/xa70xGqviux+OvhoNUSZspzl7vK7e/NTBlC+LF1zVXUXT8prrd+ZFNwKvtn0Hl +W4KfNqTM9TJB8vpE5FWnH6+B365ZvxZopZ5F/9szp9JGAUCNdX5WujBreg7nTLui +UrnDNwOvjvsE/gsoO3n3jARK+Tu8PfUl8V1bHiCeGJz/mkA9uGJ/IApcT4rYsoHB +nVQjW1NJ6A== +=zrF/ +-----END PGP MESSAGE----- + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MCqjMjAB80hAMAHfa7bdk/6L4DJQBQn+zHRv6oYzzYFC +8l79DDIE2uorQNFj1ZBw5+pi7+/2QmAANnG2ug5W0HRphg2WPXTUswy5H+mg08PM +MXRsP9lX5pAXEbLZVp61tvOQHnO/ltBhHHBwRaIq2tiirUUhy5erqLwlkSyN8xHM +Bh0u/dIJw7ewMk0l3BtF/GuP7l6PtUxT7P0Vwit4h1FV1bc9mSFmBNN16dvixJ4l +jK0mYEqT97SNZpg0MPOxx8E3xuJptzea4qmACv5zx4gYHlZRM0ZlKNqffmRauWOe +pDCjZv2F1IUJOg28NzZhKCBVhmhBmP1VmLNYFKGAsNJHAV+3uN2YYWzbhoOJAE0N +UxLI0EQN4y7OkAnGiRH45HygLxAjTk6dPiP5OD9OhUnSqofAjajlmqzfAAVMxY1a +epnRKPsnCZU= +=dqBN +-----END PGP MESSAGE----- + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MNDSEBVsF78knI+uirDbLSLrHicrXExTocmXr2DZOggI +zMYCAHyg7ohINA40/8ZuR0bC9h6qCZjjhR+VFe2edRFshXlbuzykjpXNYcSv61Sm +9TAVpgAExzS5VhAxYIJ6+zWJR8+hgv63oREZPWlJ23utBDAMkEeY7cga3wn1HZMZ +g4XQZ94a8s9s/I+s3dLOdHGdxw+hmSnxjMhI6TMcZV/Kvr1MkkW10N0h0+hiuq2O +4owEztpm4See8fCkRfhr0TO+a8ElCtIXjVwqeB0tQh0fU3QaaNiDXYawoFMQXG8N +nwCP92glfOeAvJn9KuLwO3ee+WKwcrJhsFRMmjziDdJGAUvptVDNrk2P/0fzo/Xl +ypmw8zhir6ch+4C2+5yFCtVSmC+3Y7+NQ4YE4AR/z5rGvA1lxclulU1DSGkhFTbJ +XEVyg8o23A== +=Bs3d +-----END PGP MESSAGE----- + +whoo three encrypted parts inside. diff --git a/templateparser/autotests/data/404698-gpg-inline.mbox.plain.reply b/templateparser/autotests/data/404698-gpg-inline.mbox.plain.reply new file mode 100644 index 000000000..0b58a5bd1 --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-inline.mbox.plain.reply @@ -0,0 +1,5 @@ +Please reply to this message +. +. +. + From bd031ba2ede8518f1a1bcdce7c6168f03356d6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Wed, 24 Apr 2019 00:24:40 +0200 Subject: [PATCH 07/12] TemplateParser: test htmlReply. --- .../data/404698-gpg-html.mbox.html.reply | 1 + .../data/404698-gpg-inline.mbox.html.reply | 1 + .../autotests/data/404698-gpg.mbox.html.reply | 1 + .../data/404698-smime.mbox.html.reply | 1 + .../data/html-attachment1.mbox.html.reply | 1 + .../data/html-attachment2.mbox.html.reply | 1 + .../data/openpgp-encrypted.mbox.html.reply | 1 + .../autotests/templateparserjobtest.cpp | 60 +++++++++++++++++++ .../autotests/templateparserjobtest.h | 3 + 9 files changed, 70 insertions(+) create mode 100644 templateparser/autotests/data/404698-gpg-html.mbox.html.reply create mode 100644 templateparser/autotests/data/404698-gpg-inline.mbox.html.reply create mode 100644 templateparser/autotests/data/404698-gpg.mbox.html.reply create mode 100644 templateparser/autotests/data/404698-smime.mbox.html.reply create mode 100644 templateparser/autotests/data/html-attachment1.mbox.html.reply create mode 100644 templateparser/autotests/data/html-attachment2.mbox.html.reply create mode 100644 templateparser/autotests/data/openpgp-encrypted.mbox.html.reply diff --git a/templateparser/autotests/data/404698-gpg-html.mbox.html.reply b/templateparser/autotests/data/404698-gpg-html.mbox.html.reply new file mode 100644 index 000000000..8fd2007fc --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-html.mbox.html.reply @@ -0,0 +1 @@ +Please reply to this message
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
diff --git a/templateparser/autotests/data/404698-gpg-inline.mbox.html.reply b/templateparser/autotests/data/404698-gpg-inline.mbox.html.reply new file mode 100644 index 000000000..dadcd3ced --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-inline.mbox.html.reply @@ -0,0 +1 @@ +Please reply to this message
.
.
.

diff --git a/templateparser/autotests/data/404698-gpg.mbox.html.reply b/templateparser/autotests/data/404698-gpg.mbox.html.reply new file mode 100644 index 000000000..8fd2007fc --- /dev/null +++ b/templateparser/autotests/data/404698-gpg.mbox.html.reply @@ -0,0 +1 @@ +Please reply to this message
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
diff --git a/templateparser/autotests/data/404698-smime.mbox.html.reply b/templateparser/autotests/data/404698-smime.mbox.html.reply new file mode 100644 index 000000000..8fd2007fc --- /dev/null +++ b/templateparser/autotests/data/404698-smime.mbox.html.reply @@ -0,0 +1 @@ +Please reply to this message
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
diff --git a/templateparser/autotests/data/html-attachment1.mbox.html.reply b/templateparser/autotests/data/html-attachment1.mbox.html.reply new file mode 100644 index 000000000..71b8c1c04 --- /dev/null +++ b/templateparser/autotests/data/html-attachment1.mbox.html.reply @@ -0,0 +1 @@ +

A Body Text

diff --git a/templateparser/autotests/data/html-attachment2.mbox.html.reply b/templateparser/autotests/data/html-attachment2.mbox.html.reply new file mode 100644 index 000000000..292a01964 --- /dev/null +++ b/templateparser/autotests/data/html-attachment2.mbox.html.reply @@ -0,0 +1 @@ +HTML Text diff --git a/templateparser/autotests/data/openpgp-encrypted.mbox.html.reply b/templateparser/autotests/data/openpgp-encrypted.mbox.html.reply new file mode 100644 index 000000000..578390709 --- /dev/null +++ b/templateparser/autotests/data/openpgp-encrypted.mbox.html.reply @@ -0,0 +1 @@ +encrypted text
diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index 4aba591de..78e087ec6 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -101,6 +101,66 @@ void TemplateParserJobTest::test_convertedHtml() QCOMPARE(convertedHtmlContent, referenceData); } +void TemplateParserJobTest::test_replyHtml_data() +{ + QTest::addColumn("mailFileName"); + QTest::addColumn("referenceFileName"); + + QDir dir(QStringLiteral(MAIL_DATA_DIR)); + const auto l = dir.entryList(QStringList(QStringLiteral("*.mbox")), QDir::Files | QDir::Readable | QDir::NoSymLinks); + foreach (const QString &file, l) { + const QString expectedFile = dir.path() + QLatin1Char('/') + file + QStringLiteral(".html.reply"); + if (!QFile::exists(expectedFile)) { + continue; + } + QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << expectedFile; + } +} + +void TemplateParserJobTest::test_replyHtml() +{ + QFETCH(QString, mailFileName); + QFETCH(QString, referenceFileName); + + // load input mail + QFile mailFile(mailFileName); + QVERIFY(mailFile.open(QIODevice::ReadOnly)); + const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); + QVERIFY(!mailData.isEmpty()); + KMime::Message::Ptr msg(new KMime::Message); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); + + // load expected result + QFile referenceFile(referenceFileName); + QVERIFY(referenceFile.open(QIODevice::ReadOnly)); + const QByteArray referenceRawData = KMime::CRLFtoLF(referenceFile.readAll()); + const QString referenceData = QString::fromLatin1(referenceRawData); + QVERIFY(!referenceData.isEmpty()); + + TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::NewMessage); + KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; + parser->setIdentityManager(identMan); + + parser->d->mOrigMsg = origMsg; + + QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); + parser->processWithTemplate(QString()); + QVERIFY(spy.wait()); + + QString convertedHtmlContent = parser->htmlMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); + QVERIFY(!convertedHtmlContent.isEmpty()); + + // referenceData is read from a file and most text editors add a \n at the end of the last line + if (!convertedHtmlContent.endsWith(QStringLiteral("\n"))) { + convertedHtmlContent += QStringLiteral("\n"); + } + + QCOMPARE(convertedHtmlContent, referenceData); +} + + void TemplateParserJobTest::test_replyPlain_data() { QTest::addColumn("mailFileName"); diff --git a/templateparser/autotests/templateparserjobtest.h b/templateparser/autotests/templateparserjobtest.h index 83833450c..a9158347d 100644 --- a/templateparser/autotests/templateparserjobtest.h +++ b/templateparser/autotests/templateparserjobtest.h @@ -36,6 +36,9 @@ private Q_SLOTS: void test_convertedHtml(); void test_convertedHtml_data(); + void test_replyHtml(); + void test_replyHtml_data(); + void test_replyPlain(); void test_replyPlain_data(); From 676893d23d56a31e6e9af93e40dacf9e3aa7b18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Thu, 25 Apr 2019 14:09:12 +0200 Subject: [PATCH 08/12] Rename convertedHtmlContent-> convertedHtmlContent for reply_Plain --- templateparser/autotests/templateparserjobtest.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index 78e087ec6..e6188d26a 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -210,15 +210,13 @@ void TemplateParserJobTest::test_replyPlain() //QVERIFY(parser->mOtp->htmlContent().isEmpty()); //QVERIFY(!parser->mOtp->plainTextContent().isEmpty()); -// QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); -// parser->processWithTemplate(QString()); -// QVERIFY(spy.wait()); + QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); + parser->processWithTemplate(QString()); + QVERIFY(spy.wait()); -// QBENCHMARK { -// const QString convertedHtmlContent = parser->plainMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); + const QString convertedPlainTextContent = parser->plainMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); -// QCOMPARE(convertedHtmlContent, referenceData); -// } + QCOMPARE(convertedPlainTextContent, referenceData); } void TemplateParserJobTest::test_processWithTemplatesForBody_data() From 8f9b85b664be0987014c5d2485e706ab5a198e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Thu, 25 Apr 2019 14:10:48 +0200 Subject: [PATCH 09/12] Make unexpected data leak harder via reply. ObjectTreeParser.htmlContent/plainTextContent may concats different encrypted parts without the user noticing it. That would lead to a Decryption oracle. We have already a logic to find the topleveltextNode in MimeTreeParser, this does not take HTML nodes into account nor that TEXT nodes may have several PGP Inline blocks. That plaintextContent for HtmlMessagePart is not return QString(), that bubbled up by testing the stuff. BUG: 404698 --- mimetreeparser/src/messagepart.cpp | 5 ++ mimetreeparser/src/messagepart.h | 1 + .../autotests/data/openpgp-inline-space.mbox | 31 ++++++++++ .../data/openpgp-inline-space.mbox.html.reply | 1 + .../openpgp-inline-space.mbox.plain.reply | 1 + templateparser/src/templateparserjob.cpp | 60 ++++++++++++++----- 6 files changed, 85 insertions(+), 14 deletions(-) create mode 100644 templateparser/autotests/data/openpgp-inline-space.mbox create mode 100644 templateparser/autotests/data/openpgp-inline-space.mbox.html.reply create mode 100644 templateparser/autotests/data/openpgp-inline-space.mbox.plain.reply diff --git a/mimetreeparser/src/messagepart.cpp b/mimetreeparser/src/messagepart.cpp index 991b0488e..5a64a50e7 100644 --- a/mimetreeparser/src/messagepart.cpp +++ b/mimetreeparser/src/messagepart.cpp @@ -482,6 +482,11 @@ QString HtmlMessagePart::text() const return mBodyHTML; } +QString MimeTreeParser::HtmlMessagePart::plaintextContent() const +{ + return QString(); +} + bool HtmlMessagePart::isHtml() const { return true; diff --git a/mimetreeparser/src/messagepart.h b/mimetreeparser/src/messagepart.h index 2a3e9981c..6fc608557 100644 --- a/mimetreeparser/src/messagepart.h +++ b/mimetreeparser/src/messagepart.h @@ -234,6 +234,7 @@ class MIMETREEPARSER_EXPORT HtmlMessagePart : public MessagePart ~HtmlMessagePart() override; QString text() const override; + QString plaintextContent() const override; void fix() const override; bool isHtml() const override; diff --git a/templateparser/autotests/data/openpgp-inline-space.mbox b/templateparser/autotests/data/openpgp-inline-space.mbox new file mode 100644 index 000000000..eaff262b8 --- /dev/null +++ b/templateparser/autotests/data/openpgp-inline-space.mbox @@ -0,0 +1,31 @@ +Subject: Testcase 'reply-decrytion-oracle' (PGP INLINE) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: text/plain + + + + + + + + + + + + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf7BxmM0vO8nG37hKqoqOHb35JqprJM+sqF7JFmrsuWe6V2 +PAyyE2wdtq+AhvXjVnggxYLwU+DEFpBTmWr1rsanyV8hWXRbecfN/9gN/4/N9y7Z +XSx2OeE/uA5z8Kz5vrv/ywMqcVHjB5MQPTcLC2Zlg8MVltpriy6mdAkON4I3t7kl +j9uwQRY7HeKvsib63HWnYAOV/fYPXXor/lioeYIll08uuCiTh3Z9fEhXQI/az5Ft +e/xa70xGqviux+OvhoNUSZspzl7vK7e/NTBlC+LF1zVXUXT8prrd+ZFNwKvtn0Hl +W4KfNqTM9TJB8vpE5FWnH6+B365ZvxZopZ5F/9szp9JGAUCNdX5WujBreg7nTLui +UrnDNwOvjvsE/gsoO3n3jARK+Tu8PfUl8V1bHiCeGJz/mkA9uGJ/IApcT4rYsoHB +nVQjW1NJ6A== +=zrF/ +-----END PGP MESSAGE----- + +whoo three encrypted parts inside. diff --git a/templateparser/autotests/data/openpgp-inline-space.mbox.html.reply b/templateparser/autotests/data/openpgp-inline-space.mbox.html.reply new file mode 100644 index 000000000..b78a77806 --- /dev/null +++ b/templateparser/autotests/data/openpgp-inline-space.mbox.html.reply @@ -0,0 +1 @@ +first part
diff --git a/templateparser/autotests/data/openpgp-inline-space.mbox.plain.reply b/templateparser/autotests/data/openpgp-inline-space.mbox.plain.reply new file mode 100644 index 000000000..a20785d23 --- /dev/null +++ b/templateparser/autotests/data/openpgp-inline-space.mbox.plain.reply @@ -0,0 +1 @@ +first part diff --git a/templateparser/src/templateparserjob.cpp b/templateparser/src/templateparserjob.cpp index 58dc0c30b..a93799d5f 100644 --- a/templateparser/src/templateparserjob.cpp +++ b/templateparser/src/templateparserjob.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -296,29 +297,59 @@ void TemplateParserJob::processWithIdentity(uint uoid, const KMime::Message::Ptr process(aorig_msg, afolder); } +MimeTreeParser::MessagePart::Ptr toplevelTextNode(MimeTreeParser::MessagePart::Ptr messageTree) +{ + foreach (const auto &mp, messageTree->subParts()) { + auto text = mp.dynamicCast(); + const auto attach = mp.dynamicCast(); + if (text && !attach) { + // TextMessagePart can have several subparts cause of PGP inline, we search for the first part with content + foreach (const auto &sub, mp->subParts()) { + if (!sub->text().trimmed().isEmpty()) { + return sub; + } + } + return text; + } else if (const auto html = mp.dynamicCast()) { + return html; + } else if (const auto alternative = mp.dynamicCast()) { + return alternative; + } else { + auto ret = toplevelTextNode(mp); + if (ret) { + return ret; + } + } + } + return MimeTreeParser::MessagePart::Ptr(); +} + void TemplateParserJob::processWithTemplate(const QString &tmpl) { d->mOtp->parseObjectTree(d->mOrigMsg.data()); - TemplateParserExtractHtmlInfo *job = new TemplateParserExtractHtmlInfo(this); - connect(job, &TemplateParserExtractHtmlInfo::finished, this, &TemplateParserJob::slotExtractInfoDone); + const auto mp = toplevelTextNode(d->mOtp->parsedPart()); - QString plainText = d->mOtp->plainTextContent(); - if (plainText.isEmpty()) { //HTML-only mails - plainText = d->mOtp->htmlContent(); - } + QString plainText = mp->plaintextContent(); + QString htmlElement; - job->setHtmlForExtractingTextPlain(plainText); - job->setTemplate(tmpl); - - QString htmlElement = d->mOtp->htmlContent(); - - if (htmlElement.isEmpty()) { //plain mails only - QString htmlReplace = d->mOtp->plainTextContent().toHtmlEscaped(); + if (mp->isHtml()) { + htmlElement = d->mOtp->htmlContent(); + if (plainText.isEmpty()) { //HTML-only mails + plainText = htmlElement; + } + } else { //plain mails only + QString htmlReplace = plainText.toHtmlEscaped(); htmlReplace = htmlReplace.replace(QLatin1Char('\n'), QStringLiteral("
")); htmlElement = QStringLiteral("%1\n").arg(htmlReplace); } + TemplateParserExtractHtmlInfo *job = new TemplateParserExtractHtmlInfo(this); + connect(job, &TemplateParserExtractHtmlInfo::finished, this, &TemplateParserJob::slotExtractInfoDone); + + job->setHtmlForExtractingTextPlain(plainText); + job->setTemplate(tmpl); + job->setHtmlForExtractionHeaderAndBody(htmlElement); job->start(); } @@ -1483,7 +1514,8 @@ QString TemplateParserJob::plainMessageText(bool aStripSignature, AllowSelection if (!d->mOrigMsg) { return QString(); } - QString result = d->mOtp->plainTextContent(); + const auto mp = toplevelTextNode(d->mOtp->parsedPart()); + QString result = mp->plaintextContent(); if (result.isEmpty()) { result = d->mExtractHtmlInfoResult.mPlainText; } From ac360b3a57eacbf0542ed0800e6054db76f01398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Fri, 26 Apr 2019 17:34:31 +0200 Subject: [PATCH 10/12] Decryption Oracle based on forwarding PGP or S/MIME mails (CVE-2019-10732) Summary: Add test coverage for mail forwarding. BUG: 404698 Test Plan: all tests passes forward (text/html): [x] PGP Mime text [x] PGP Mime html [x] S/MIME [x] PGP inline Reviewers: #kde_pim, vkrause, aacid, dfaure Subscribers: kde-pim, security-team Tags: #kde_pim Differential Revision: https://phabricator.kde.org/D20847 --- .../data/404698-gpg-attachments.mbox | 72 ++++++++ ...404698-gpg-attachments.mbox.forwarded.mbox | 66 +++++++ .../404698-gpg-attachments.mbox.html.reply | 1 + .../404698-gpg-attachments.mbox.plain.reply | 5 + .../data/html-attachment1.mbox.forwarded.mbox | 83 +++++++++ .../data/html-attachment2.mbox.forwarded.mbox | 28 +++ .../autotests/templateparserjobtest.cpp | 162 ++++++++++++++++++ .../autotests/templateparserjobtest.h | 9 + 8 files changed, 426 insertions(+) create mode 100644 templateparser/autotests/data/404698-gpg-attachments.mbox create mode 100644 templateparser/autotests/data/404698-gpg-attachments.mbox.forwarded.mbox create mode 100644 templateparser/autotests/data/404698-gpg-attachments.mbox.html.reply create mode 100644 templateparser/autotests/data/404698-gpg-attachments.mbox.plain.reply create mode 100644 templateparser/autotests/data/html-attachment1.mbox.forwarded.mbox create mode 100644 templateparser/autotests/data/html-attachment2.mbox.forwarded.mbox diff --git a/templateparser/autotests/data/404698-gpg-attachments.mbox b/templateparser/autotests/data/404698-gpg-attachments.mbox new file mode 100644 index 000000000..83c2d169d --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-attachments.mbox @@ -0,0 +1,72 @@ +Subject: Testcase 'reply-mix-crlf' (PGP/MIME HTML) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain + +Please reply to this message +. +. +. + + +--BOUNDARY +Content-Type: text/plain; name="text1.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf7BxmM0vO8nG37hKqoqOHb35JqprJM+sqF7JFmrsuWe6V2 +PAyyE2wdtq+AhvXjVnggxYLwU+DEFpBTmWr1rsanyV8hWXRbecfN/9gN/4/N9y7Z +XSx2OeE/uA5z8Kz5vrv/ywMqcVHjB5MQPTcLC2Zlg8MVltpriy6mdAkON4I3t7kl +j9uwQRY7HeKvsib63HWnYAOV/fYPXXor/lioeYIll08uuCiTh3Z9fEhXQI/az5Ft +e/xa70xGqviux+OvhoNUSZspzl7vK7e/NTBlC+LF1zVXUXT8prrd+ZFNwKvtn0Hl +W4KfNqTM9TJB8vpE5FWnH6+B365ZvxZopZ5F/9szp9JGAUCNdX5WujBreg7nTLui +UrnDNwOvjvsE/gsoO3n3jARK+Tu8PfUl8V1bHiCeGJz/mkA9uGJ/IApcT4rYsoHB +nVQjW1NJ6A== +=zrF/ +-----END PGP MESSAGE----- + +--BOUNDARY +Content-Type: text/plain; name="text2.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MCqjMjAB80hAMAHfa7bdk/6L4DJQBQn+zHRv6oYzzYFC +8l79DDIE2uorQNFj1ZBw5+pi7+/2QmAANnG2ug5W0HRphg2WPXTUswy5H+mg08PM +MXRsP9lX5pAXEbLZVp61tvOQHnO/ltBhHHBwRaIq2tiirUUhy5erqLwlkSyN8xHM +Bh0u/dIJw7ewMk0l3BtF/GuP7l6PtUxT7P0Vwit4h1FV1bc9mSFmBNN16dvixJ4l +jK0mYEqT97SNZpg0MPOxx8E3xuJptzea4qmACv5zx4gYHlZRM0ZlKNqffmRauWOe +pDCjZv2F1IUJOg28NzZhKCBVhmhBmP1VmLNYFKGAsNJHAV+3uN2YYWzbhoOJAE0N +UxLI0EQN4y7OkAnGiRH45HygLxAjTk6dPiP5OD9OhUnSqofAjajlmqzfAAVMxY1a +epnRKPsnCZU= +=dqBN +-----END PGP MESSAGE----- + + +--BOUNDARY +Content-Type: text/plain; name="text3.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MNDSEBVsF78knI+uirDbLSLrHicrXExTocmXr2DZOggI +zMYCAHyg7ohINA40/8ZuR0bC9h6qCZjjhR+VFe2edRFshXlbuzykjpXNYcSv61Sm +9TAVpgAExzS5VhAxYIJ6+zWJR8+hgv63oREZPWlJ23utBDAMkEeY7cga3wn1HZMZ +g4XQZ94a8s9s/I+s3dLOdHGdxw+hmSnxjMhI6TMcZV/Kvr1MkkW10N0h0+hiuq2O +4owEztpm4See8fCkRfhr0TO+a8ElCtIXjVwqeB0tQh0fU3QaaNiDXYawoFMQXG8N +nwCP92glfOeAvJn9KuLwO3ee+WKwcrJhsFRMmjziDdJGAUvptVDNrk2P/0fzo/Xl +ypmw8zhir6ch+4C2+5yFCtVSmC+3Y7+NQ4YE4AR/z5rGvA1lxclulU1DSGkhFTbJ +XEVyg8o23A== +=Bs3d +-----END PGP MESSAGE----- + +--BOUNDARY + +whoo three encrypted parts inside. + +--BOUNDRY-- diff --git a/templateparser/autotests/data/404698-gpg-attachments.mbox.forwarded.mbox b/templateparser/autotests/data/404698-gpg-attachments.mbox.forwarded.mbox new file mode 100644 index 000000000..1b3a24a05 --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-attachments.mbox.forwarded.mbox @@ -0,0 +1,66 @@ +Subject: Testcase 'reply-mix-crlf' (PGP/MIME HTML) +To: brucewayne45@web.de +From: brucewayne45@web.de +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="BOUNDARY" + +--BOUNDARY +Content-Type: text/plain + +Please reply to this message +. +. +. + + +--BOUNDARY +Content-Type: text/plain; name="text1.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf7BxmM0vO8nG37hKqoqOHb35JqprJM+sqF7JFmrsuWe6V2 +PAyyE2wdtq+AhvXjVnggxYLwU+DEFpBTmWr1rsanyV8hWXRbecfN/9gN/4/N9y7Z +XSx2OeE/uA5z8Kz5vrv/ywMqcVHjB5MQPTcLC2Zlg8MVltpriy6mdAkON4I3t7kl +j9uwQRY7HeKvsib63HWnYAOV/fYPXXor/lioeYIll08uuCiTh3Z9fEhXQI/az5Ft +e/xa70xGqviux+OvhoNUSZspzl7vK7e/NTBlC+LF1zVXUXT8prrd+ZFNwKvtn0Hl +W4KfNqTM9TJB8vpE5FWnH6+B365ZvxZopZ5F/9szp9JGAUCNdX5WujBreg7nTLui +UrnDNwOvjvsE/gsoO3n3jARK+Tu8PfUl8V1bHiCeGJz/mkA9uGJ/IApcT4rYsoHB +nVQjW1NJ6A== +=zrF/ +-----END PGP MESSAGE----- + +--BOUNDARY +Content-Type: text/plain; name="text2.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MCqjMjAB80hAMAHfa7bdk/6L4DJQBQn+zHRv6oYzzYFC +8l79DDIE2uorQNFj1ZBw5+pi7+/2QmAANnG2ug5W0HRphg2WPXTUswy5H+mg08PM +MXRsP9lX5pAXEbLZVp61tvOQHnO/ltBhHHBwRaIq2tiirUUhy5erqLwlkSyN8xHM +Bh0u/dIJw7ewMk0l3BtF/GuP7l6PtUxT7P0Vwit4h1FV1bc9mSFmBNN16dvixJ4l +jK0mYEqT97SNZpg0MPOxx8E3xuJptzea4qmACv5zx4gYHlZRM0ZlKNqffmRauWOe +pDCjZv2F1IUJOg28NzZhKCBVhmhBmP1VmLNYFKGAsNJHAV+3uN2YYWzbhoOJAE0N +UxLI0EQN4y7OkAnGiRH45HygLxAjTk6dPiP5OD9OhUnSqofAjajlmqzfAAVMxY1a +epnRKPsnCZU= +=dqBN +-----END PGP MESSAGE----- + + +--BOUNDARY +Content-Type: text/plain; name="text3.txt" +Content-Disposition: inline + +-----BEGIN PGP MESSAGE----- + +hQEMAwzOQ1qnzNo7AQf+MNDSEBVsF78knI+uirDbLSLrHicrXExTocmXr2DZOggI +zMYCAHyg7ohINA40/8ZuR0bC9h6qCZjjhR+VFe2edRFshXlbuzykjpXNYcSv61Sm +9TAVpgAExzS5VhAxYIJ6+zWJR8+hgv63oREZPWlJ23utBDAMkEeY7cga3wn1HZMZ +g4XQZ94a8s9s/I+s3dLOdHGdxw+hmSnxjMhI6TMcZV/Kvr1MkkW10N0h0+hiuq2O +4owEztpm4See8fCkRfhr0TO+a8ElCtIXjVwqeB0tQh0fU3QaaNiDXYawoFMQXG8N +nwCP92glfOeAvJn9KuLwO3ee+WKwcrJhsFRMmjziDdJGAUvptVDNrk2P/0fzo/Xl +ypmw8zhir6ch+4C2+5yFCtVSmC+3Y7+NQ4YE4AR/z5rGvA1lxclulU1DSGkhFTbJ +XEVyg8o23A== +=Bs3d +-----END PGP MESSAGE----- diff --git a/templateparser/autotests/data/404698-gpg-attachments.mbox.html.reply b/templateparser/autotests/data/404698-gpg-attachments.mbox.html.reply new file mode 100644 index 000000000..dadcd3ced --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-attachments.mbox.html.reply @@ -0,0 +1 @@ +Please reply to this message
.
.
.

diff --git a/templateparser/autotests/data/404698-gpg-attachments.mbox.plain.reply b/templateparser/autotests/data/404698-gpg-attachments.mbox.plain.reply new file mode 100644 index 000000000..0b58a5bd1 --- /dev/null +++ b/templateparser/autotests/data/404698-gpg-attachments.mbox.plain.reply @@ -0,0 +1,5 @@ +Please reply to this message +. +. +. + diff --git a/templateparser/autotests/data/html-attachment1.mbox.forwarded.mbox b/templateparser/autotests/data/html-attachment1.mbox.forwarded.mbox new file mode 100644 index 000000000..b4df51a9e --- /dev/null +++ b/templateparser/autotests/data/html-attachment1.mbox.forwarded.mbox @@ -0,0 +1,83 @@ +Return-path: +Envelope-to: gunter@ohrner.net +Delivery-date: Mon, 12 Sep 2016 13:38:39 +0200 +Received: from mail.from example.com ([178.251.88.150]) + by luggage.ohrner.net with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:256) + (Exim 4.80) + (envelope-from ) + id 1bjPYi-0000oA-Re + for gunter@ohrner.net; Mon, 12 Sep 2016 13:38:39 +0200 +Received: from example.com.local (172.17.124.205) by from example.com.local + (172.17.124.1) with Microsoft SMTP Server id 14.3.266.1; Mon, 12 Sep 2016 + 13:37:53 +0200 +From: +To: +Message-ID: <8614416.18.1473680273823.JavaMail.sender@example.com> +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_Part_16_9312243.1473680273820" +Date: Mon, 12 Sep 2016 13:37:53 +0200 +X-TM-AS-Product-Ver: SMEX-11.1.0.1278-8.000.1202-22570.004 +X-TM-AS-Result: No--23.664000-5.000000-31 +X-TM-AS-User-Approved-Sender: No +X-TM-AS-User-Blocked-Sender: No +Subject: A Subject Line + +------=_Part_16_9312243.1473680273820 +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: 8bit + +

A Body Text

+------=_Part_16_9312243.1473680273820 +Content-Type: application/pdf; name="Attachment1.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment + +JVBERi0xLjEKJeLjz9MKMSAwIG9iaiAKPDwKL1R5cGUgL0NhdGFsb2cKL1BhZ2VzIDIgMCBSCj4+ +CmVuZG9iaiAKMiAwIG9iaiAKPDwKL0tpZHMgWzMgMCBSXQovVHlwZSAvUGFnZXMKL01lZGlhQm94 +IFswIDAgMzAwIDE0NF0KL0NvdW50IDEKPj4KZW5kb2JqIAozIDAgb2JqIAo8PAovUmVzb3VyY2Vz +IAo8PAovRm9udCAKPDwKL0YxIAo8PAovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKL0Jhc2VG +b250IC9UaW1lcy1Sb21hbgo+Pgo+Pgo+PgovQ29udGVudHMgNCAwIFIKL1BhcmVudCAyIDAgUgov +VHlwZSAvUGFnZQovTWVkaWFCb3ggWzAgMCAzMDAgMTQ0XQo+PgplbmRvYmogCjQgMCBvYmogCjw8 +Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggNTIKPj4Kc3RyZWFtCnicU1BwCuFSAAJ9N0MF +QwuFkDQwzwAIQ1LATA2P1JycfIXw/KKcFE2FkCygoGsIACsbDAQKZW5kc3RyZWFtIAplbmRvYmog +eHJlZgowIDUKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDAw +NjYgMDAwMDAgbiAKMDAwMDAwMDE0OSAwMDAwMCBuIAowMDAwMDAwMzMxIDAwMDAwIG4gCnRyYWls +ZXIKCjw8Ci9Sb290IDEgMCBSCi9TaXplIDUKPj4Kc3RhcnR4cmVmCjQ1NgolJUVPRgo= + +------=_Part_16_9312243.1473680273820 +Content-Type: application/pdf; name="Attachment2.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment + +JVBERi0xLjEKJeLjz9MKMSAwIG9iaiAKPDwKL1R5cGUgL0NhdGFsb2cKL1BhZ2VzIDIgMCBSCj4+ +CmVuZG9iaiAKMiAwIG9iaiAKPDwKL0tpZHMgWzMgMCBSXQovVHlwZSAvUGFnZXMKL01lZGlhQm94 +IFswIDAgMzAwIDE0NF0KL0NvdW50IDEKPj4KZW5kb2JqIAozIDAgb2JqIAo8PAovUmVzb3VyY2Vz +IAo8PAovRm9udCAKPDwKL0YxIAo8PAovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKL0Jhc2VG +b250IC9UaW1lcy1Sb21hbgo+Pgo+Pgo+PgovQ29udGVudHMgNCAwIFIKL1BhcmVudCAyIDAgUgov +VHlwZSAvUGFnZQovTWVkaWFCb3ggWzAgMCAzMDAgMTQ0XQo+PgplbmRvYmogCjQgMCBvYmogCjw8 +Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggNTIKPj4Kc3RyZWFtCnicU1BwCuFSAAJ9N0MF +QwuFkDQwzwAIQ1LATA2P1JycfIXw/KKcFE2FkCygoGsIACsbDAQKZW5kc3RyZWFtIAplbmRvYmog +eHJlZgowIDUKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDAw +NjYgMDAwMDAgbiAKMDAwMDAwMDE0OSAwMDAwMCBuIAowMDAwMDAwMzMxIDAwMDAwIG4gCnRyYWls +ZXIKCjw8Ci9Sb290IDEgMCBSCi9TaXplIDUKPj4Kc3RhcnR4cmVmCjQ1NgolJUVPRgo= + +------=_Part_16_9312243.1473680273820 +Content-Type: application/pdf; name="Attachment3.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment + +JVBERi0xLjEKJeLjz9MKMSAwIG9iaiAKPDwKL1R5cGUgL0NhdGFsb2cKL1BhZ2VzIDIgMCBSCj4+ +CmVuZG9iaiAKMiAwIG9iaiAKPDwKL0tpZHMgWzMgMCBSXQovVHlwZSAvUGFnZXMKL01lZGlhQm94 +IFswIDAgMzAwIDE0NF0KL0NvdW50IDEKPj4KZW5kb2JqIAozIDAgb2JqIAo8PAovUmVzb3VyY2Vz +IAo8PAovRm9udCAKPDwKL0YxIAo8PAovU3VidHlwZSAvVHlwZTEKL1R5cGUgL0ZvbnQKL0Jhc2VG +b250IC9UaW1lcy1Sb21hbgo+Pgo+Pgo+PgovQ29udGVudHMgNCAwIFIKL1BhcmVudCAyIDAgUgov +VHlwZSAvUGFnZQovTWVkaWFCb3ggWzAgMCAzMDAgMTQ0XQo+PgplbmRvYmogCjQgMCBvYmogCjw8 +Ci9GaWx0ZXIgL0ZsYXRlRGVjb2RlCi9MZW5ndGggNTIKPj4Kc3RyZWFtCnicU1BwCuFSAAJ9N0MF +QwuFkDQwzwAIQ1LATA2P1JycfIXw/KKcFE2FkCygoGsIACsbDAQKZW5kc3RyZWFtIAplbmRvYmog +eHJlZgowIDUKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDAw +NjYgMDAwMDAgbiAKMDAwMDAwMDE0OSAwMDAwMCBuIAowMDAwMDAwMzMxIDAwMDAwIG4gCnRyYWls +ZXIKCjw8Ci9Sb290IDEgMCBSCi9TaXplIDUKPj4Kc3RhcnR4cmVmCjQ1NgolJUVPRgo= + +------=_Part_16_9312243.1473680273820-- + diff --git a/templateparser/autotests/data/html-attachment2.mbox.forwarded.mbox b/templateparser/autotests/data/html-attachment2.mbox.forwarded.mbox new file mode 100644 index 000000000..498cf3a9d --- /dev/null +++ b/templateparser/autotests/data/html-attachment2.mbox.forwarded.mbox @@ -0,0 +1,28 @@ +From maillists@whattf.com Tue Jul 05 19:20:58 2011 +Return-path: +Envelope-to: maillists@whattf.com +Date: Mon, 24 Oct 2016 11:53:00 +0100 +To: maillists@whattf.com +From: maillists@whattf.com +MIME-Version: 1.0 +Subject: Test +Content-Type: multipart/related; boundary="----=_Part_20324_1054669183.1477306380301" +MIME-Version: 1.0 + +------=_Part_20324_1054669183.1477306380301 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: 7bit + +HTML Text +------=_Part_20324_1054669183.1477306380301 +Content-Type: image/png +Content-Disposition: attachment; filename="image1.png" + +Image1 +------=_Part_20324_1054669183.1477306380301 +Content-Type: image/png +Content-Disposition: attachment; filename="image2.png" + +Image2 +------=_Part_20324_1054669183.1477306380301-- + diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index e6188d26a..acca8210f 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -219,6 +219,168 @@ void TemplateParserJobTest::test_replyPlain() QCOMPARE(convertedPlainTextContent, referenceData); } +void TemplateParserJobTest::test_forwardPlain_data() +{ + QTest::addColumn("mailFileName"); + QTest::addColumn("referenceFileName"); + + QDir dir(QStringLiteral(MAIL_DATA_DIR)); + const auto l = dir.entryList(QStringList(QStringLiteral("*.mbox")), QDir::Files | QDir::Readable | QDir::NoSymLinks); + foreach (const QString &file, l) { + const QString expectedFile = dir.path() + QLatin1Char('/') + file + QStringLiteral(".plain.reply"); + if (!QFile::exists(expectedFile)) { + continue; + } + QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << expectedFile; + } +} + +void TemplateParserJobTest::test_forwardPlain() +{ + QFETCH(QString, mailFileName); + QFETCH(QString, referenceFileName); + + // load input mail + QFile mailFile(mailFileName); + QVERIFY(mailFile.open(QIODevice::ReadOnly)); + const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); + QVERIFY(!mailData.isEmpty()); + KMime::Message::Ptr msg(new KMime::Message); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); + + // load expected result + QFile referenceFile(referenceFileName); + QVERIFY(referenceFile.open(QIODevice::ReadOnly)); + const QByteArray referenceRawData = KMime::CRLFtoLF(referenceFile.readAll()); + const QString referenceData = QString::fromLatin1(referenceRawData); + QVERIFY(!referenceData.isEmpty()); + + TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Forward); + parser->d->mOrigMsg = origMsg; + + QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); + parser->processWithTemplate(QString()); + QVERIFY(spy.wait()); + + const QString convertedPlainTextContent = parser->plainMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); + + QCOMPARE(convertedPlainTextContent, referenceData); +} + +void TemplateParserJobTest::test_forwardHtml_data() +{ + QTest::addColumn("mailFileName"); + QTest::addColumn("referenceFileName"); + + QDir dir(QStringLiteral(MAIL_DATA_DIR)); + const auto l = dir.entryList(QStringList(QStringLiteral("*.mbox")), QDir::Files | QDir::Readable | QDir::NoSymLinks); + foreach (const QString &file, l) { + const QString expectedFile = dir.path() + QLatin1Char('/') + file + QStringLiteral(".html.reply"); + if (!QFile::exists(expectedFile)) { + continue; + } + QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << expectedFile; + } +} + +void TemplateParserJobTest::test_forwardHtml() +{ + QFETCH(QString, mailFileName); + QFETCH(QString, referenceFileName); + + // load input mail + QFile mailFile(mailFileName); + QVERIFY(mailFile.open(QIODevice::ReadOnly)); + const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); + QVERIFY(!mailData.isEmpty()); + KMime::Message::Ptr msg(new KMime::Message); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); + + // load expected result + QFile referenceFile(referenceFileName); + QVERIFY(referenceFile.open(QIODevice::ReadOnly)); + const QByteArray referenceRawData = KMime::CRLFtoLF(referenceFile.readAll()); + const QString referenceData = QString::fromLatin1(referenceRawData); + QVERIFY(!referenceData.isEmpty()); + + TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Forward); + parser->d->mOrigMsg = origMsg; + + QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); + parser->processWithTemplate(QString()); + QVERIFY(spy.wait()); + + QString convertedHtmlContent = parser->htmlMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); + // referenceData is read from a file and most text editors add a \n at the end of the last line + if (!convertedHtmlContent.endsWith(QStringLiteral("\n"))) { + convertedHtmlContent += QStringLiteral("\n"); + } + + QCOMPARE(convertedHtmlContent, referenceData); +} + +void TemplateParserJobTest::test_forwardedAttachments_data() +{ + QTest::addColumn("mailFileName"); + QTest::addColumn("referenceFileName"); + + QDir dir(QStringLiteral(MAIL_DATA_DIR)); + const auto l = dir.entryList(QStringList(QStringLiteral("*.mbox")), QDir::Files | QDir::Readable | QDir::NoSymLinks); + foreach (const QString &file, l) { + if (!QFile::exists(dir.path() + QLatin1Char('/') + file + QStringLiteral(".html.reply"))) { + continue; + } + QString expectedFile = dir.path() + QLatin1Char('/') + file + QStringLiteral(".forwarded.mbox"); + QTest::newRow(file.toLatin1().constData()) << QString(dir.path() + QLatin1Char('/') + file) << expectedFile; + } +} + +void TemplateParserJobTest::test_forwardedAttachments() +{ + QFETCH(QString, mailFileName); + QFETCH(QString, referenceFileName); + + // load input mail + QFile mailFile(mailFileName); + QVERIFY(mailFile.open(QIODevice::ReadOnly)); + const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); + QVERIFY(!mailData.isEmpty()); + KMime::Message::Ptr msg(new KMime::Message); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); + + bool referenceExists = QFile::exists(referenceFileName); + + TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Forward); + parser->d->mOrigMsg = origMsg; + + QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); + parser->processWithTemplate(QString()); + QVERIFY(spy.wait()); + + if (referenceExists) { + QFile referenceFile(referenceFileName); + QVERIFY(referenceFile.open(QIODevice::ReadOnly)); + const QByteArray referenceRawData = KMime::CRLFtoLF(referenceFile.readAll()); + const KMime::Message::Ptr referenceMsg(new KMime::Message); + referenceMsg->setContent(referenceRawData); + referenceMsg->parse(); + + QCOMPARE(msg->contents().size(), referenceMsg->contents().size()); + for (int i=1; i < msg->contents().size(); i++) { + QCOMPARE(msg->contents()[i]->encodedContent(), referenceMsg->contents()[i]->encodedContent()); + } + } else { + QCOMPARE(msg->contents().size(), 0); + } + +} + void TemplateParserJobTest::test_processWithTemplatesForBody_data() { QTest::addColumn("command"); diff --git a/templateparser/autotests/templateparserjobtest.h b/templateparser/autotests/templateparserjobtest.h index a9158347d..f7771e8a2 100644 --- a/templateparser/autotests/templateparserjobtest.h +++ b/templateparser/autotests/templateparserjobtest.h @@ -42,6 +42,15 @@ private Q_SLOTS: void test_replyPlain(); void test_replyPlain_data(); + void test_forwardPlain(); + void test_forwardPlain_data(); + + void test_forwardHtml(); + void test_forwardHtml_data(); + + void test_forwardedAttachments(); + void test_forwardedAttachments_data(); + /** * Tests whether templates are returning required body or not */ From d7f78cc22e3adf24b969759372f203cd4bddb815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Mon, 22 Apr 2019 21:51:23 +0200 Subject: [PATCH 11/12] Refresh TemplateParserJobTest::test_convertedHtml logic Summary: Use internal logic to parse the mail instead of triggering the parsing externally and make it compatible with other tests. TemplateParser differs between `mMsg`(write) and `mOrigMsg` (read). If we use `msg` everywhere, this leads to asserts. Reviewers: #kde_pim Subscribers: kde-pim Tags: #kde_pim Differential Revision: https://phabricator.kde.org/D20755 --- .../autotests/templateparserjobtest.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index acca8210f..4a607907c 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -71,8 +71,11 @@ void TemplateParserJobTest::test_convertedHtml() const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); QVERIFY(!mailData.isEmpty()); KMime::Message::Ptr msg(new KMime::Message); - msg->setContent(mailData); - msg->parse(); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); + QCOMPARE(origMsg->subject()->as7BitString(false).constData(), "Plain Message Test"); + QCOMPARE(origMsg->contents().size(), 0); // load expected result QFile referenceFile(referenceFileName); @@ -81,19 +84,18 @@ void TemplateParserJobTest::test_convertedHtml() const QString referenceData = QString::fromLatin1(referenceRawData); QVERIFY(!referenceData.isEmpty()); - QCOMPARE(msg->subject()->as7BitString(false).constData(), "Plain Message Test"); - QCOMPARE(msg->contents().size(), 0); TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::NewMessage); KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; parser->setIdentityManager(identMan); - parser->d->mOtp->parseObjectTree(msg.data()); - QVERIFY(parser->d->mOtp->htmlContent().isEmpty()); - QVERIFY(!parser->d->mOtp->plainTextContent().isEmpty()); + + parser->d->mOrigMsg = origMsg; QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); parser->processWithTemplate(QString()); QVERIFY(spy.wait()); + QVERIFY(parser->d->mOtp->htmlContent().isEmpty()); + QVERIFY(!parser->d->mOtp->plainTextContent().isEmpty()); const QString convertedHtmlContent = parser->htmlMessageText(false, TemplateParser::TemplateParserJob::NoSelectionAllowed); QVERIFY(!convertedHtmlContent.isEmpty()); From a5d0ad10ced249d74819209ae22052fde481e426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20Knau=C3=9F?= Date: Mon, 22 Apr 2019 22:24:33 +0200 Subject: [PATCH 12/12] enable TemplateParserJobTest::test_replyPlain again. Summary: processWithTemplate does modify `msg` so we endup with invalid pointers, if there are related images added for the reply. Reviewers: #kde_pim Subscribers: kde-pim Tags: #kde_pim Differential Revision: https://phabricator.kde.org/D20753 --- .../autotests/templateparserjobtest.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/templateparser/autotests/templateparserjobtest.cpp b/templateparser/autotests/templateparserjobtest.cpp index 4a607907c..6cae9c44d 100644 --- a/templateparser/autotests/templateparserjobtest.cpp +++ b/templateparser/autotests/templateparserjobtest.cpp @@ -190,27 +190,19 @@ void TemplateParserJobTest::test_replyPlain() const QByteArray mailData = KMime::CRLFtoLF(mailFile.readAll()); QVERIFY(!mailData.isEmpty()); KMime::Message::Ptr msg(new KMime::Message); - msg->setContent(mailData); - msg->parse(); + KMime::Message::Ptr origMsg(new KMime::Message); + origMsg->setContent(mailData); + origMsg->parse(); // load expected result QFile referenceFile(referenceFileName); QVERIFY(referenceFile.open(QIODevice::ReadOnly)); const QByteArray referenceRawData = KMime::CRLFtoLF(referenceFile.readAll()); const QString referenceData = QString::fromLatin1(referenceRawData); -// QVERIFY(!referenceData.isEmpty()); - -// QCOMPARE(msg->subject()->as7BitString(false).constData(), "Plain Message Test"); -// QCOMPARE(msg->contents().size(), 0); + QVERIFY(!referenceData.isEmpty()); TemplateParser::TemplateParserJob *parser = new TemplateParser::TemplateParserJob(msg, TemplateParser::TemplateParserJob::Reply); - //KIdentityManagement::IdentityManager *identMan = new KIdentityManagement::IdentityManager; - //parser->setIdentityManager(identMan); - - parser->d->mOtp->parseObjectTree(msg.data()); - parser->d->mOrigMsg = msg; - //QVERIFY(parser->mOtp->htmlContent().isEmpty()); - //QVERIFY(!parser->mOtp->plainTextContent().isEmpty()); + parser->d->mOrigMsg = origMsg; QSignalSpy spy(parser, &TemplateParser::TemplateParserJob::parsingDone); parser->processWithTemplate(QString());