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 }