File indexing completed on 2025-03-09 04:54:13

0001 /*
0002    SPDX-FileCopyrightText: 2020 Sandro Kanuß <sknauss@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "autocryptutils.h"
0008 
0009 #include "autocryptstorage.h"
0010 
0011 #include "autocrypt_debug.h"
0012 
0013 #include <QHash>
0014 
0015 using namespace MessageCore;
0016 
0017 HeaderMixupNodeHelper::HeaderMixupNodeHelper(MimeTreeParser::NodeHelper *n, KMime::Content *m)
0018     : message(m)
0019     , mNodeHelper(n)
0020 {
0021 }
0022 
0023 QDateTime HeaderMixupNodeHelper::dateHeader() const
0024 {
0025     return mNodeHelper->dateHeader(message);
0026 }
0027 
0028 bool HeaderMixupNodeHelper::hasMailHeader(const char *header) const
0029 {
0030     return mNodeHelper->hasMailHeader(header, message);
0031 }
0032 
0033 QSharedPointer<KMime::Headers::Generics::AddressList> HeaderMixupNodeHelper::mailHeaderAsAddressList(const char *header) const
0034 {
0035     return mNodeHelper->mailHeaderAsAddressList(header, message);
0036 }
0037 
0038 const KMime::Headers::Base *HeaderMixupNodeHelper::mailHeaderAsBase(const char *header) const
0039 {
0040     return mNodeHelper->mailHeaderAsBase(header, message);
0041 }
0042 
0043 QList<MimeTreeParser::MessagePart::Ptr> HeaderMixupNodeHelper::messagePartsOfMailHeader(const char *header) const
0044 {
0045     return mNodeHelper->messagePartsOfMailHeader(header, message);
0046 }
0047 
0048 QList<KMime::Headers::Base *> HeaderMixupNodeHelper::headers(const char *header) const
0049 {
0050     return mNodeHelper->headers(header, message);
0051 }
0052 
0053 QHash<QByteArray, QByteArray> MessageCore::paramsFromAutocryptHeader(const KMime::Headers::Base *const header)
0054 {
0055     QHash<QByteArray, QByteArray> params;
0056 
0057     const auto &parts = header->as7BitString(false).split(';');
0058     for (const auto &part : parts) {
0059         const auto &i = part.split('=');
0060         params[i[0].trimmed()] = i[1].trimmed();
0061     }
0062     return params;
0063 }
0064 
0065 void MessageCore::processAutocryptfromMail(const HeaderMixupNodeHelper &mixup)
0066 {
0067     auto storage = AutocryptStorage::self();
0068 
0069     QByteArray messageid = "<NO Message-ID header>";
0070     if (mixup.mailHeaderAsBase("Message-ID")) {
0071         messageid = mixup.mailHeaderAsBase("Message-ID")->as7BitString(false);
0072     }
0073 
0074     const auto fromAddr = mixup.mailHeaderAsAddressList("from");
0075     if (fromAddr->addresses().size() != 1) {
0076         qInfo(AUTOCRYPT_LOG) << "Don't update Autocrypt storage, none or multiple From headers found in " << messageid;
0077         return;
0078     }
0079 
0080     if (mixup.hasMailHeader("Autocrypt")) {
0081         KMime::Headers::Base *header = nullptr;
0082         int valid = 0;
0083         for (const auto h : mixup.headers("Autocrypt")) {
0084             const auto params = paramsFromAutocryptHeader(h);
0085             if (params.value("addr") != fromAddr->addresses().value(0)) {
0086                 continue;
0087             }
0088             bool invalid = false;
0089             for (const auto &key : params.keys()) {
0090                 if (key == "addr") {
0091                     continue;
0092                 } else if (key == "prefer-encrypt") {
0093                     continue;
0094                 } else if (key == "keydata") {
0095                     continue;
0096                 } else if (key[0] == '_') {
0097                     continue;
0098                 } else {
0099                     invalid = true;
0100                     break;
0101                 }
0102             }
0103             if (invalid) {
0104                 continue;
0105             }
0106             if (!header) {
0107                 header = h;
0108             }
0109             valid++;
0110         }
0111         if (valid == 1) {
0112             const auto params = paramsFromAutocryptHeader(header);
0113             auto recipient = storage->addRecipient(params.value("addr"));
0114             recipient->updateFromMessage(mixup, header);
0115             qInfo(AUTOCRYPT_LOG) << "Update Autocrypt information for " << recipient->addr() << " from " << messageid;
0116         } else {
0117             qInfo(AUTOCRYPT_LOG) << "Don't update Autocrypt storage, because we have multiple valid Autocrypt headers found in " << messageid;
0118         }
0119     } else {
0120         auto recipient = storage->getRecipient(fromAddr->addresses().value(0));
0121         if (recipient) {
0122             recipient->updateFromMessage(mixup, nullptr);
0123             qInfo(AUTOCRYPT_LOG) << "Update Autocrypt information for " << recipient->addr() << " from " << messageid;
0124         }
0125     }
0126 
0127     if (mixup.hasMailHeader("Autocrypt-Gossip")) {
0128         MimeTreeParser::MessagePart::Ptr messagePart(nullptr);
0129         for (const auto &mp : mixup.messagePartsOfMailHeader("Autocrypt-Gossip")) {
0130             if (mp.staticCast<MimeTreeParser::EncryptedMessagePart>()) {
0131                 messagePart = mp;
0132                 break;
0133             }
0134         }
0135         if (messagePart) {
0136             for (const auto &header : messagePart->headers("Autocrypt-Gossip")) {
0137                 const auto params = paramsFromAutocryptHeader(header);
0138                 auto recipient = storage->addRecipient(params.value("addr"));
0139                 recipient->updateFromGossip(mixup, header);
0140                 qInfo(AUTOCRYPT_LOG) << "Update Autocrypt Gossip information for" << recipient->addr() << " from " << messageid;
0141             }
0142         }
0143     }
0144     storage->save();
0145 }