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

0001 /*
0002    SPDX-FileCopyrightText: 2020 Sandro Kanuß <sknauss@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "autocryptrecipient.h"
0008 #include "autocryptrecipient_p.h"
0009 #include "autocryptutils.h"
0010 
0011 #include <KCodecs>
0012 #include <QGpgME/DataProvider>
0013 #include <QGpgME/Protocol>
0014 #include <QJsonObject>
0015 #include <gpgme++/data.h>
0016 
0017 using namespace MessageCore;
0018 
0019 AutocryptRecipientPrivate::AutocryptRecipientPrivate() = default;
0020 
0021 QByteArray AutocryptRecipientPrivate::toJson(QJsonDocument::JsonFormat format) const
0022 {
0023     QJsonObject entry;
0024     entry.insert(QStringLiteral("addr"), QString::fromLatin1(addr));
0025     entry.insert(QStringLiteral("prefer_encrypt"), prefer_encrypt);
0026     entry.insert(QStringLiteral("keydata"), QString::fromLatin1(keydata));
0027     entry.insert(QStringLiteral("autocrypt_timestamp"), autocrypt_timestamp.toString(Qt::ISODate));
0028     entry.insert(QStringLiteral("count_have_ach"), count_have_ach);
0029     entry.insert(QStringLiteral("count_no_ach"), count_no_ach);
0030     if (last_seen.isValid()) {
0031         entry.insert(QStringLiteral("last_seen"), last_seen.toString(Qt::ISODate));
0032     }
0033     if (counting_since.isValid()) {
0034         entry.insert(QStringLiteral("counting_since"), counting_since.toString(Qt::ISODate));
0035     }
0036     if (!bad_user_agent.isEmpty()) {
0037         entry.insert(QStringLiteral("bad_user_agent"), QString::fromLatin1(bad_user_agent));
0038     }
0039     if (gossip_timestamp.isValid()) {
0040         entry.insert(QStringLiteral("gossip_timestamp"), gossip_timestamp.toString(Qt::ISODate));
0041         entry.insert(QStringLiteral("gossip_key"), QString::fromLatin1(gossip_key));
0042     }
0043     QJsonDocument document;
0044     document.setObject(entry);
0045     return document.toJson(format);
0046 }
0047 
0048 void AutocryptRecipientPrivate::fromJson(const QByteArray &json)
0049 {
0050     auto document = QJsonDocument::fromJson(json);
0051     assert(document.isObject());
0052     const auto &obj = document.object();
0053 
0054     addr = obj.value(QStringLiteral("addr")).toString().toLatin1();
0055     count_have_ach = obj.value(QStringLiteral("count_have_ach")).toInt();
0056     count_no_ach = obj.value(QStringLiteral("count_no_ach")).toInt();
0057     prefer_encrypt = obj.value(QStringLiteral("prefer_encrypt")).toBool();
0058     keydata = obj.value(QStringLiteral("keydata")).toString().toLatin1();
0059     autocrypt_timestamp = QDateTime::fromString(obj.value(QStringLiteral("autocrypt_timestamp")).toString(), Qt::ISODate);
0060 
0061     if (obj.contains(QStringLiteral("last_seen"))) {
0062         last_seen = QDateTime::fromString(obj.value(QStringLiteral("last_seen")).toString(), Qt::ISODate);
0063     } else {
0064         last_seen = QDateTime();
0065     }
0066 
0067     if (obj.contains(QStringLiteral("counting_since"))) {
0068         counting_since = QDateTime::fromString(obj.value(QStringLiteral("counting_since")).toString(), Qt::ISODate);
0069     } else {
0070         counting_since = QDateTime();
0071     }
0072 
0073     if (obj.contains(QStringLiteral("bad_user_agent"))) {
0074         bad_user_agent = obj.value(QStringLiteral("bad_user_agent")).toString().toLatin1();
0075     } else {
0076         bad_user_agent = "";
0077     }
0078 
0079     if (obj.contains(QStringLiteral("gossip_timestamp"))) {
0080         gossip_timestamp = QDateTime::fromString(obj.value(QStringLiteral("gossip_timestamp")).toString(), Qt::ISODate);
0081         gossip_key = obj.value(QStringLiteral("gossip_key")).toString().toLatin1();
0082     } else {
0083         gossip_timestamp = QDateTime();
0084         gossip_key = "";
0085     }
0086     changed = false;
0087 }
0088 
0089 AutocryptRecipient::AutocryptRecipient()
0090     : d_ptr(new AutocryptRecipientPrivate())
0091 {
0092 }
0093 
0094 void AutocryptRecipient::updateFromMessage(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
0095 {
0096     Q_D(AutocryptRecipient);
0097     QDateTime effectiveDate = mixup.dateHeader();
0098 
0099     if (effectiveDate > QDateTime::currentDateTime()) {
0100         return;
0101     }
0102 
0103     if (d->autocrypt_timestamp.isValid() && effectiveDate <= d->autocrypt_timestamp) {
0104         return;
0105     }
0106 
0107     d->autocrypt_timestamp = effectiveDate;
0108     d->changed = true;
0109 
0110     if (!d->counting_since.isValid()) {
0111         d->counting_since = effectiveDate;
0112         d->count_have_ach = 0;
0113         d->count_no_ach = 0;
0114     }
0115 
0116     if (header) {
0117         const auto params = paramsFromAutocryptHeader(header);
0118         if (d->addr.isEmpty()) {
0119             d->addr = params.value("addr");
0120         }
0121         d->prefer_encrypt = params.contains("prefer-encrypt");
0122         d->keydata = params.value("keydata");
0123         d->keydata.replace(' ', QByteArray());
0124 
0125         d->last_seen = effectiveDate;
0126         d->count_have_ach += 1;
0127     } else {
0128         d->count_no_ach += 1;
0129         if (mixup.hasMailHeader("User-Agent")) {
0130             d->bad_user_agent = mixup.mailHeaderAsBase("User-Agent")->as7BitString(false);
0131         }
0132     }
0133 }
0134 
0135 void AutocryptRecipient::updateFromGossip(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
0136 {
0137     Q_D(AutocryptRecipient);
0138     QDateTime effectiveDate = mixup.dateHeader();
0139 
0140     if (effectiveDate > QDateTime::currentDateTime()) {
0141         return;
0142     }
0143 
0144     if (d->gossip_timestamp.isValid() && effectiveDate <= d->gossip_timestamp) {
0145         return;
0146     }
0147 
0148     const auto params = paramsFromAutocryptHeader(header);
0149 
0150     if (d->addr.isEmpty()) {
0151         d->addr = params.value("addr");
0152     } else if (d->addr != params.value("addr")) {
0153         return;
0154     }
0155 
0156     d->changed = true;
0157     d->gossip_timestamp = effectiveDate;
0158     d->gossip_key = params.value("keydata");
0159     d->gossip_key.replace(' ', QByteArray());
0160 }
0161 
0162 QByteArray AutocryptRecipient::toJson(QJsonDocument::JsonFormat format) const
0163 {
0164     const Q_D(AutocryptRecipient);
0165     return d->toJson(format);
0166 }
0167 
0168 void AutocryptRecipient::fromJson(const QByteArray &json)
0169 {
0170     Q_D(AutocryptRecipient);
0171     return d->fromJson(json);
0172 }
0173 
0174 bool AutocryptRecipient::hasChanged() const
0175 {
0176     const Q_D(AutocryptRecipient);
0177     return d->changed;
0178 }
0179 
0180 void AutocryptRecipient::setChangedFlag(bool changed)
0181 {
0182     Q_D(AutocryptRecipient);
0183     d->changed = changed;
0184 }
0185 
0186 GpgME::Key gpgKey(const QByteArray &keydata)
0187 {
0188     assert(QGpgME::openpgp()); // Make sure, that openpgp backend is loaded
0189     auto context = GpgME::Context::create(GpgME::OpenPGP);
0190     QGpgME::QByteArrayDataProvider dp(KCodecs::base64Decode(keydata));
0191     GpgME::Data data(&dp);
0192     const auto keys = data.toKeys();
0193     if (keys.size() == 0) {
0194         return {};
0195     }
0196     return keys[0];
0197 }
0198 
0199 GpgME::Key MessageCore::AutocryptRecipient::gpgKey() const
0200 {
0201     const Q_D(AutocryptRecipient);
0202     return ::gpgKey(d->keydata);
0203 }
0204 
0205 QByteArray MessageCore::AutocryptRecipient::gpgKeydata() const
0206 {
0207     const Q_D(AutocryptRecipient);
0208     return KCodecs::base64Decode(d->keydata);
0209 }
0210 
0211 GpgME::Key AutocryptRecipient::gossipKey() const
0212 {
0213     const Q_D(AutocryptRecipient);
0214     return ::gpgKey(d->gossip_key);
0215 }
0216 
0217 QByteArray MessageCore::AutocryptRecipient::gossipKeydata() const
0218 {
0219     const Q_D(AutocryptRecipient);
0220     return KCodecs::base64Decode(d->gossip_key);
0221 }
0222 
0223 QByteArray AutocryptRecipient::addr() const
0224 {
0225     const Q_D(AutocryptRecipient);
0226     return d->addr;
0227 }
0228 
0229 QByteArray AutocryptRecipient::bad_user_agent() const
0230 {
0231     const Q_D(AutocryptRecipient);
0232     return d->bad_user_agent;
0233 }
0234 
0235 QDateTime AutocryptRecipient::last_seen() const
0236 {
0237     const Q_D(AutocryptRecipient);
0238     return d->last_seen;
0239 }
0240 
0241 QDateTime AutocryptRecipient::autocrypt_timestamp() const
0242 {
0243     const Q_D(AutocryptRecipient);
0244     return d->autocrypt_timestamp;
0245 }
0246 
0247 QDateTime AutocryptRecipient::counting_since() const
0248 {
0249     const Q_D(AutocryptRecipient);
0250     return d->counting_since;
0251 }
0252 
0253 QDateTime AutocryptRecipient::gossip_timestamp() const
0254 {
0255     const Q_D(AutocryptRecipient);
0256     return d->gossip_timestamp;
0257 }
0258 
0259 int AutocryptRecipient::count_have_ach() const
0260 {
0261     const Q_D(AutocryptRecipient);
0262     return d->count_have_ach;
0263 }
0264 
0265 int AutocryptRecipient::count_no_ach() const
0266 {
0267     const Q_D(AutocryptRecipient);
0268     return d->count_no_ach;
0269 }
0270 
0271 bool AutocryptRecipient::prefer_encrypt() const
0272 {
0273     const Q_D(AutocryptRecipient);
0274     return d->prefer_encrypt;
0275 }