File indexing completed on 2024-06-23 05:19:20
0001 /* 0002 SPDX-FileCopyrightText: 2017 Sandro Knauß <sknauss@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "encrypted.h" 0008 0009 #include "messagepart.h" 0010 #include "objecttreeparser.h" 0011 0012 #include <KMime/Content> 0013 0014 #include <QGpgME/DataProvider> 0015 #include <QGpgME/Protocol> 0016 #include <gpgme++/data.h> 0017 0018 #include "mimetreeparser_debug.h" 0019 0020 using namespace MimeTreeParser; 0021 0022 const Interface::BodyPartFormatter *EncryptedBodyPartFormatter::create(EncryptedBodyPartFormatter::EncryptionFlags flags) 0023 { 0024 auto self = new EncryptedBodyPartFormatter; 0025 self->mFlags = flags; 0026 return self; 0027 } 0028 0029 MessagePart::Ptr EncryptedBodyPartFormatter::process(Interface::BodyPart &part) const 0030 { 0031 KMime::Content *node = part.content(); 0032 const auto nodeHelper = part.nodeHelper(); 0033 0034 if (!node->contents().isEmpty()) { 0035 Q_ASSERT(false); 0036 return {}; 0037 } 0038 0039 const QByteArray content(node->decodedContent()); 0040 if (content.isEmpty()) { 0041 return nullptr; 0042 } 0043 0044 if (!(mFlags & EncryptedBodyPartFormatter::ForcePGP)) { 0045 // If not forcing the data to be interpreted as PGP encrypted, 0046 // only check for encryption if it starts with a 7-bit ASCII 0047 // character. Valid armored PGP data always starts with an 0048 // ASCII character, so if the first byte has bit 8 set then it 0049 // cannot be PGP armored. This way we retain support for armored 0050 // inline PGP data, but avoid random binary data being detected 0051 // as PGP data. See bug 390002 and messagelib!83. 0052 unsigned char firstByte = content[0]; 0053 if ((firstByte & 0x80) != 0) { 0054 return nullptr; 0055 } 0056 0057 QGpgME::QByteArrayDataProvider dp(content); 0058 GpgME::Data data(&dp); 0059 0060 if (data.type() == GpgME::Data::Unknown) { 0061 return nullptr; 0062 } 0063 } 0064 0065 const QGpgME::Protocol *useThisCryptProto = nullptr; 0066 0067 useThisCryptProto = QGpgME::openpgp(); 0068 0069 // TODO: Load correct crypto Proto 0070 0071 nodeHelper->setEncryptionState(node, KMMsgFullyEncrypted); 0072 0073 EncryptedMessagePart::Ptr mp( 0074 new EncryptedMessagePart(part.objectTreeParser(), node->decodedText(), useThisCryptProto, nodeHelper->fromAsString(node), node)); 0075 mp->setIsEncrypted(true); 0076 mp->setDecryptMessage(part.source()->decryptMessage()); 0077 PartMetaData *messagePart(mp->partMetaData()); 0078 0079 if (!part.source()->decryptMessage()) { 0080 nodeHelper->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed 0081 } else if (KMime::Content *newNode = nodeHelper->decryptedNodeForContent(node)) { 0082 // if we already have a decrypted node for part.objectTreeParser() encrypted node, don't do the decryption again 0083 return MessagePart::Ptr(new MimeMessagePart(part.objectTreeParser(), newNode, true)); 0084 } else { 0085 // Codec of the decrypted content is not delivered. 0086 // Gnupgp tells that you should use UTF-8 by default. 0087 // The user has the possibility to override the default charset. 0088 0089 QByteArray codecName = "utf-8"; 0090 if (!part.source()->overrideCodecName().isEmpty()) { 0091 codecName = part.source()->overrideCodecName(); 0092 } 0093 0094 mp->startDecryption(node->decodedContent(), codecName); 0095 qCDebug(MIMETREEPARSER_LOG) << "decrypted, signed?:" << messagePart->isSigned; 0096 0097 if (!messagePart->inProgress) { 0098 if (!messagePart->isEncrypted) { 0099 return nullptr; 0100 } 0101 auto tempNode = new KMime::Content(); 0102 tempNode->setBody(KMime::CRLFtoLF(mp->text().toUtf8())); 0103 tempNode->parse(); 0104 // inside startDecryption we use toCodec and we 0105 // converted the decoded text to utf-8 already. 0106 tempNode->contentType()->setCharset("utf-8"); 0107 0108 NodeHelper::magicSetType(tempNode); 0109 if (node->topLevel()->textContent() != node && node->contentDisposition(false) && !tempNode->contentDisposition(false)) { 0110 tempNode->contentDisposition()->setDisposition(node->contentDisposition()->disposition()); 0111 const auto fname = node->contentDisposition(false)->filename(); 0112 if (!fname.isEmpty()) { 0113 tempNode->contentDisposition(false)->setFilename(fname); 0114 } 0115 } 0116 0117 if (!tempNode->head().isEmpty()) { 0118 tempNode->contentDescription()->from7BitString("decrypted data"); 0119 } 0120 tempNode->assemble(); 0121 0122 nodeHelper->cleanExtraContent(node); 0123 mp->clearSubParts(); 0124 0125 nodeHelper->attachExtraContent(node, tempNode); 0126 0127 mp->parseInternal(tempNode, false); 0128 0129 nodeHelper->setNodeProcessed(node, false); // Set the data node to done to prevent it from being processed 0130 } 0131 } 0132 return mp; 0133 }