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 }