File indexing completed on 2025-03-09 04:53:53
0001 /* 0002 SPDX-FileCopyrightText: 2014-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only 0005 */ 0006 0007 #include "composerviewbasetest.h" 0008 #include "cryptofunctions.h" 0009 #include "qtest_messagecomposer.h" 0010 #include "setupenv.h" 0011 0012 #include <MessageComposer/Composer> 0013 #include <MessageComposer/ComposerViewBase> 0014 #include <MessageComposer/MessageComposerSettings> 0015 #include <MessageComposer/RecipientsEditor> 0016 #include <MessageComposer/RichTextComposerNg> 0017 0018 #include <MessageCore/NodeHelper> 0019 0020 #include <MimeTreeParser/ObjectTreeParser> 0021 #include <MimeTreeParser/SimpleObjectTreeSource> 0022 0023 #include <KIdentityManagementCore/Identity> 0024 #include <KIdentityManagementCore/IdentityManager> 0025 #include <KIdentityManagementWidgets/IdentityCombo> 0026 0027 #include <MailTransport/TransportComboBox> 0028 0029 #include <QStandardPaths> 0030 #include <QTest> 0031 0032 using namespace MessageComposer; 0033 0034 Q_DECLARE_METATYPE(Kleo::CryptoMessageFormat) 0035 0036 QTEST_MAIN(ComposerViewBaseTest) 0037 0038 ComposerViewBaseTest::ComposerViewBaseTest(QObject *parent) 0039 : QObject(parent) 0040 { 0041 Test::setupEnv(); 0042 } 0043 0044 ComposerViewBaseTest::~ComposerViewBaseTest() = default; 0045 0046 void ComposerViewBaseTest::cleanupTestCase() 0047 { 0048 delete mIdentMan; 0049 mIdentMan = nullptr; 0050 delete mIdentCombo; 0051 mIdentCombo = nullptr; 0052 } 0053 0054 void ComposerViewBaseTest::initTestCase() 0055 { 0056 mIdentMan = new KIdentityManagementCore::IdentityManager; 0057 0058 KIdentityManagementCore::Identity &ident = mIdentMan->modifyIdentityForUoid(mIdentMan->defaultIdentity().uoid()); 0059 ident.setAutocryptEnabled(true); 0060 ident.setPGPEncryptionKey("1BA323932B3FAA826132C79E8D9860C58F246DE6"); 0061 ident.setPGPSigningKey("1BA323932B3FAA826132C79E8D9860C58F246DE6"); 0062 mIdentMan->commit(); 0063 mIdentCombo = new KIdentityManagementWidgets::IdentityCombo(mIdentMan); 0064 0065 MessageComposerSettings::self()->setCryptoShowKeysForApproval(false); 0066 0067 const QDir genericDataLocation(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); 0068 autocryptDir = QDir(genericDataLocation.filePath(QStringLiteral("autocrypt"))); 0069 } 0070 0071 void ComposerViewBaseTest::init() 0072 { 0073 autocryptDir.removeRecursively(); 0074 autocryptDir.mkpath(QStringLiteral(".")); 0075 } 0076 0077 void ComposerViewBaseTest::cleanup() 0078 { 0079 autocryptDir.removeRecursively(); 0080 } 0081 0082 void ComposerViewBaseTest::shouldHaveDefaultValue() 0083 { 0084 ComposerViewBase composerViewBase; 0085 QVERIFY(!composerViewBase.attachmentModel()); 0086 QVERIFY(!composerViewBase.attachmentController()); 0087 QVERIFY(!composerViewBase.recipientsEditor()); 0088 QVERIFY(!composerViewBase.signatureController()); 0089 QVERIFY(!composerViewBase.identityCombo()); 0090 QVERIFY(!composerViewBase.identityManager()); 0091 QVERIFY(!composerViewBase.editor()); 0092 QVERIFY(!composerViewBase.transportComboBox()); 0093 QVERIFY(!composerViewBase.fccCombo()); 0094 QVERIFY(!composerViewBase.dictionary()); 0095 QVERIFY(composerViewBase.to().isEmpty()); 0096 QVERIFY(composerViewBase.cc().isEmpty()); 0097 QVERIFY(composerViewBase.bcc().isEmpty()); 0098 QVERIFY(composerViewBase.from().isEmpty()); 0099 QVERIFY(composerViewBase.replyTo().isEmpty()); 0100 QVERIFY(composerViewBase.subject().isEmpty()); 0101 QCOMPARE(composerViewBase.autoSaveInterval(), 60000); 0102 } 0103 0104 void ComposerViewBaseTest::testAutoSaveMessage() 0105 { 0106 QString fileName(QStringLiteral("testfile")); 0107 0108 MessageComposer::RichTextComposerNg editor; 0109 MessageComposer::RecipientsEditor recipientsEditor; 0110 MailTransport::TransportComboBox transpCombo; 0111 ComposerViewBase composerViewBase; 0112 composerViewBase.setAutoSaveInterval(0); 0113 composerViewBase.setAutoSaveFileName(fileName); 0114 composerViewBase.setIdentityCombo(mIdentCombo); 0115 composerViewBase.setIdentityManager(mIdentMan); 0116 composerViewBase.setEditor(&editor); 0117 composerViewBase.setTransportCombo(&transpCombo); 0118 composerViewBase.setRecipientsEditor(&recipientsEditor); 0119 composerViewBase.setFrom(QStringLiteral("me@me.example")); 0120 KMime::Types::Mailbox mb; 0121 mb.from7BitString("to@to.example"); 0122 recipientsEditor.setRecipientString({mb}, Recipient::To); 0123 editor.setPlainText(QStringLiteral("Hello,\n\nThis is a test message\n\nGreez")); 0124 0125 composerViewBase.autoSaveMessage(); 0126 0127 // It may be possible that we need to wait till the autosave message is ready composed. 0128 if (composerViewBase.m_composers.size() > 0) { 0129 QEventLoop loop; 0130 bool notFinished = false; 0131 for (const auto composer : composerViewBase.m_composers) { 0132 if (!composer->finished()) { 0133 notFinished = true; 0134 connect(composer, &MessageComposer::Composer::result, [&composerViewBase, &loop]() { 0135 if (composerViewBase.m_composers.size() < 1) { 0136 loop.quit(); 0137 } 0138 }); 0139 } 0140 } 0141 if (notFinished) { 0142 loop.exec(); 0143 } 0144 } 0145 0146 const QString autosavePath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1StringView("/kmail2/autosave/"); 0147 auto msg = Test::loadMessage(autosavePath + fileName); 0148 msg->messageID()->from7BitString("<test@autotest.example>"); 0149 msg->date()->from7BitString("Tue, 22 Jan 2019 12:56:25 +0100"); 0150 msg->assemble(); 0151 Test::compareFile(msg.data(), QStringLiteral(MAIL_DATA_DIR "/autosave.mbox")); 0152 } 0153 0154 void ComposerViewBaseTest::testGenerateCryptoMessagesAutocrypt_data() 0155 { 0156 QTest::addColumn<QString>("data"); 0157 QTest::addColumn<bool>("sign"); 0158 QTest::addColumn<bool>("encrypt"); 0159 QTest::addColumn<Kleo::CryptoMessageFormat>("format"); 0160 0161 QString data = QStringLiteral("Hello,\n\nThis is a test message\n\nGreez"); 0162 0163 QTest::newRow("Plain") << data << false << false << Kleo::AutoFormat; 0164 QTest::newRow("Sign") << data << true << false << Kleo::AutoFormat; 0165 QTest::newRow("Encrypt") << data << false << true << Kleo::AutoFormat; 0166 QTest::newRow("SignEncrypt") << data << true << true << Kleo::AutoFormat; 0167 } 0168 0169 void ComposerViewBaseTest::testGenerateCryptoMessagesAutocrypt() 0170 { 0171 QFETCH(QString, data); 0172 QFETCH(bool, sign); 0173 QFETCH(bool, encrypt); 0174 QFETCH(Kleo::CryptoMessageFormat, format); 0175 0176 MessageComposer::RichTextComposerNg editor; 0177 MessageComposer::RecipientsEditor recipientsEditor; 0178 MailTransport::TransportComboBox transpCombo; 0179 ComposerViewBase composerViewBase; 0180 composerViewBase.setIdentityCombo(mIdentCombo); 0181 composerViewBase.setIdentityManager(mIdentMan); 0182 composerViewBase.setEditor(&editor); 0183 composerViewBase.setTransportCombo(&transpCombo); 0184 composerViewBase.setRecipientsEditor(&recipientsEditor); 0185 composerViewBase.setFrom(QStringLiteral("me@me.example")); 0186 composerViewBase.mExpandedTo << QStringLiteral("you@you.com"); 0187 composerViewBase.setAkonadiLookupEnabled(false); 0188 KMime::Types::Mailbox mb; 0189 mb.from7BitString("you@you.com"); 0190 recipientsEditor.setRecipientString({mb}, Recipient::To); 0191 editor.setPlainText(data); 0192 0193 bool wasCanceled = false; 0194 composerViewBase.setCryptoOptions(sign, encrypt, format, false); 0195 auto composers = composerViewBase.generateCryptoMessages(wasCanceled); 0196 QCOMPARE(wasCanceled, false); 0197 0198 QCOMPARE(composers.size(), 1); // No additional composers are created 0199 0200 auto composer = composers.first(); 0201 composerViewBase.fillComposer(composer); 0202 0203 VERIFYEXEC(composer); 0204 0205 QCOMPARE(composer->resultMessages().size(), 1); 0206 0207 auto msg = composer->resultMessages().first(); 0208 msg->assemble(); 0209 0210 // Every message should have an Autocrypt in the outer message structure 0211 // as it should always been possible to start an encrypted reply 0212 QCOMPARE(msg->hasHeader("Autocrypt"), true); 0213 0214 MimeTreeParser::SimpleObjectTreeSource testSource; 0215 testSource.setDecryptMessage(true); 0216 auto nh = new MimeTreeParser::NodeHelper; 0217 MimeTreeParser::ObjectTreeParser otp(&testSource, nh); 0218 0219 otp.parseObjectTree(msg.data()); 0220 0221 KMime::Content *content = msg.data(); 0222 0223 if (encrypt) { 0224 QCOMPARE(nh->encryptionState(msg.data()), MimeTreeParser::KMMsgFullyEncrypted); 0225 const auto extra = nh->extraContents(msg.data()); 0226 QCOMPARE(extra.size(), 1); 0227 content = extra.first(); 0228 } else { 0229 QCOMPARE(nh->encryptionState(msg.data()), MimeTreeParser::KMMsgNotEncrypted); 0230 } 0231 0232 if (sign) { 0233 content = MessageCore::NodeHelper::firstChild(content); 0234 QCOMPARE(nh->signatureState(content), MimeTreeParser::KMMsgFullySigned); 0235 } else { 0236 QCOMPARE(nh->signatureState(msg.data()), MimeTreeParser::KMMsgNotSigned); 0237 } 0238 0239 QCOMPARE(QString::fromUtf8(content->decodedContent()), data); 0240 } 0241 0242 void ComposerViewBaseTest::testGenerateCryptoMessagesAutocryptSMime() 0243 { 0244 QString data = QStringLiteral("Hello,\n\nThis is a test message\n\nGreez"); 0245 0246 MessageComposer::RichTextComposerNg editor; 0247 MessageComposer::RecipientsEditor recipientsEditor; 0248 MailTransport::TransportComboBox transpCombo; 0249 ComposerViewBase composerViewBase; 0250 composerViewBase.setIdentityCombo(mIdentCombo); 0251 composerViewBase.setIdentityManager(mIdentMan); 0252 composerViewBase.setEditor(&editor); 0253 composerViewBase.setTransportCombo(&transpCombo); 0254 composerViewBase.setRecipientsEditor(&recipientsEditor); 0255 composerViewBase.setFrom(QStringLiteral("me@me.example")); 0256 composerViewBase.mExpandedTo << QStringLiteral("you@you.com"); 0257 composerViewBase.setAkonadiLookupEnabled(false); 0258 KMime::Types::Mailbox mb; 0259 mb.from7BitString("you@you.com"); 0260 recipientsEditor.setRecipientString({mb}, Recipient::To); 0261 editor.setPlainText(data); 0262 0263 bool wasCanceled = false; 0264 composerViewBase.setCryptoOptions(false, false, Kleo::AnySMIME, false); 0265 auto composers = composerViewBase.generateCryptoMessages(wasCanceled); 0266 QCOMPARE(wasCanceled, false); 0267 0268 QCOMPARE(composers.size(), 1); // No additional composers are created 0269 0270 auto composer = composers.first(); 0271 composerViewBase.fillComposer(composer); 0272 0273 VERIFYEXEC(composer); 0274 0275 QCOMPARE(composer->resultMessages().size(), 1); 0276 0277 auto msg = composer->resultMessages().first(); 0278 msg->assemble(); 0279 0280 QCOMPARE(QString::fromUtf8(msg->decodedContent()), data); 0281 QCOMPARE(msg->hasHeader("Autocrypt"), false); 0282 } 0283 0284 void ComposerViewBaseTest::testAutocryptKey() 0285 { 0286 QFile file(QLatin1StringView(MESSAGECORE_DATA_DIR) + QStringLiteral("/autocrypt/recipient.json")); 0287 QVERIFY(file.copy(autocryptDir.path() + QStringLiteral("/recipient%40autocrypt.example.json"))); 0288 0289 qDebug() << autocryptDir.path(); 0290 0291 QString data = QStringLiteral("Hello,\n\nThis is a test message\n\nGreez"); 0292 0293 MessageComposer::RichTextComposerNg editor; 0294 MessageComposer::RecipientsEditor recipientsEditor; 0295 MailTransport::TransportComboBox transpCombo; 0296 ComposerViewBase composerViewBase; 0297 composerViewBase.setIdentityCombo(mIdentCombo); 0298 composerViewBase.setIdentityManager(mIdentMan); 0299 composerViewBase.setEditor(&editor); 0300 composerViewBase.setTransportCombo(&transpCombo); 0301 composerViewBase.setRecipientsEditor(&recipientsEditor); 0302 composerViewBase.setFrom(QStringLiteral("me@me.example")); 0303 composerViewBase.mExpandedTo << QStringLiteral("recipient@autocrypt.example"); 0304 composerViewBase.setAkonadiLookupEnabled(false); 0305 KMime::Types::Mailbox mb; 0306 mb.from7BitString("recipient@autocrypt.example"); 0307 recipientsEditor.setRecipientString({mb}, Recipient::To); 0308 editor.setPlainText(data); 0309 0310 bool wasCanceled = false; 0311 composerViewBase.setCryptoOptions(false, true, Kleo::AutoFormat, false); 0312 auto composers = composerViewBase.generateCryptoMessages(wasCanceled); 0313 QCOMPARE(wasCanceled, false); 0314 0315 QCOMPARE(composers.size(), 1); // No additional composers are created 0316 0317 auto composer = composers.first(); 0318 composerViewBase.fillComposer(composer); 0319 0320 VERIFYEXEC(composer); 0321 0322 QCOMPARE(composer->resultMessages().size(), 1); 0323 0324 // The key for recipient@autocrypt.example is only available in Autocrypt 0325 // test is we created a special GNUPGHOME to contain all needed keys. 0326 QVERIFY(!composer->gnupgHome().isEmpty()); 0327 0328 auto msg = composer->resultMessages().first(); 0329 msg->assemble(); 0330 0331 // Every message should have an Autocrypt in the outer message structure 0332 // as it should always been possible to start an encrypted reply 0333 QCOMPARE(msg->hasHeader("Autocrypt"), true); 0334 0335 MimeTreeParser::SimpleObjectTreeSource testSource; 0336 testSource.setDecryptMessage(true); 0337 auto nh = new MimeTreeParser::NodeHelper; 0338 MimeTreeParser::ObjectTreeParser otp(&testSource, nh); 0339 0340 otp.parseObjectTree(msg.data()); 0341 0342 KMime::Content *content = msg.data(); 0343 0344 QCOMPARE(nh->encryptionState(msg.data()), MimeTreeParser::KMMsgFullyEncrypted); 0345 const auto extra = nh->extraContents(msg.data()); 0346 QCOMPARE(extra.size(), 1); 0347 content = extra.first(); 0348 0349 QCOMPARE(QString::fromUtf8(content->decodedContent()), data); 0350 } 0351 0352 #include "moc_composerviewbasetest.cpp"