Messagelib

autocryptrecipient.cpp
1/*
2 SPDX-FileCopyrightText: 2020 Sandro Kanuß <sknauss@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "autocryptrecipient.h"
8#include "autocryptrecipient_p.h"
9#include "autocryptutils.h"
10
11#include <KCodecs>
12#include <QGpgME/DataProvider>
13#include <QGpgME/Protocol>
14#include <QJsonObject>
15#include <gpgme++/data.h>
16
17using namespace MessageCore;
18
19AutocryptRecipientPrivate::AutocryptRecipientPrivate() = default;
20
21QByteArray AutocryptRecipientPrivate::toJson(QJsonDocument::JsonFormat format) const
22{
23 QJsonObject entry;
24 entry.insert(QStringLiteral("addr"), QString::fromLatin1(addr));
25 entry.insert(QStringLiteral("prefer_encrypt"), prefer_encrypt);
26 entry.insert(QStringLiteral("keydata"), QString::fromLatin1(keydata));
27 entry.insert(QStringLiteral("autocrypt_timestamp"), autocrypt_timestamp.toString(Qt::ISODate));
28 entry.insert(QStringLiteral("count_have_ach"), count_have_ach);
29 entry.insert(QStringLiteral("count_no_ach"), count_no_ach);
30 if (last_seen.isValid()) {
31 entry.insert(QStringLiteral("last_seen"), last_seen.toString(Qt::ISODate));
32 }
33 if (counting_since.isValid()) {
34 entry.insert(QStringLiteral("counting_since"), counting_since.toString(Qt::ISODate));
35 }
36 if (!bad_user_agent.isEmpty()) {
37 entry.insert(QStringLiteral("bad_user_agent"), QString::fromLatin1(bad_user_agent));
38 }
39 if (gossip_timestamp.isValid()) {
40 entry.insert(QStringLiteral("gossip_timestamp"), gossip_timestamp.toString(Qt::ISODate));
41 entry.insert(QStringLiteral("gossip_key"), QString::fromLatin1(gossip_key));
42 }
43 QJsonDocument document;
44 document.setObject(entry);
45 return document.toJson(format);
46}
47
48void AutocryptRecipientPrivate::fromJson(const QByteArray &json)
49{
50 auto document = QJsonDocument::fromJson(json);
51 assert(document.isObject());
52 const auto &obj = document.object();
53
54 addr = obj.value(QStringLiteral("addr")).toString().toLatin1();
55 count_have_ach = obj.value(QStringLiteral("count_have_ach")).toInt();
56 count_no_ach = obj.value(QStringLiteral("count_no_ach")).toInt();
57 prefer_encrypt = obj.value(QStringLiteral("prefer_encrypt")).toBool();
58 keydata = obj.value(QStringLiteral("keydata")).toString().toLatin1();
59 autocrypt_timestamp = QDateTime::fromString(obj.value(QStringLiteral("autocrypt_timestamp")).toString(), Qt::ISODate);
60
61 if (obj.contains(QStringLiteral("last_seen"))) {
62 last_seen = QDateTime::fromString(obj.value(QStringLiteral("last_seen")).toString(), Qt::ISODate);
63 } else {
64 last_seen = QDateTime();
65 }
66
67 if (obj.contains(QStringLiteral("counting_since"))) {
68 counting_since = QDateTime::fromString(obj.value(QStringLiteral("counting_since")).toString(), Qt::ISODate);
69 } else {
70 counting_since = QDateTime();
71 }
72
73 if (obj.contains(QStringLiteral("bad_user_agent"))) {
74 bad_user_agent = obj.value(QStringLiteral("bad_user_agent")).toString().toLatin1();
75 } else {
76 bad_user_agent = "";
77 }
78
79 if (obj.contains(QStringLiteral("gossip_timestamp"))) {
80 gossip_timestamp = QDateTime::fromString(obj.value(QStringLiteral("gossip_timestamp")).toString(), Qt::ISODate);
81 gossip_key = obj.value(QStringLiteral("gossip_key")).toString().toLatin1();
82 } else {
83 gossip_timestamp = QDateTime();
84 gossip_key = "";
85 }
86 changed = false;
87}
88
89AutocryptRecipient::AutocryptRecipient()
90 : d_ptr(new AutocryptRecipientPrivate())
91{
92}
93
94void AutocryptRecipient::updateFromMessage(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
95{
96 Q_D(AutocryptRecipient);
97 QDateTime effectiveDate = mixup.dateHeader();
98
99 if (effectiveDate > QDateTime::currentDateTime()) {
100 return;
101 }
102
103 if (d->autocrypt_timestamp.isValid() && effectiveDate <= d->autocrypt_timestamp) {
104 return;
105 }
106
107 d->autocrypt_timestamp = effectiveDate;
108 d->changed = true;
109
110 if (!d->counting_since.isValid()) {
111 d->counting_since = effectiveDate;
112 d->count_have_ach = 0;
113 d->count_no_ach = 0;
114 }
115
116 if (header) {
117 const auto params = paramsFromAutocryptHeader(header);
118 if (d->addr.isEmpty()) {
119 d->addr = params.value("addr");
120 }
121 d->prefer_encrypt = params.contains("prefer-encrypt");
122 d->keydata = params.value("keydata");
123 d->keydata.replace(' ', QByteArray());
124
125 d->last_seen = effectiveDate;
126 d->count_have_ach += 1;
127 } else {
128 d->count_no_ach += 1;
129 if (mixup.hasMailHeader("User-Agent")) {
130 d->bad_user_agent = mixup.mailHeaderAsBase("User-Agent")->as7BitString(false);
131 }
132 }
133}
134
135void AutocryptRecipient::updateFromGossip(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
136{
137 Q_D(AutocryptRecipient);
138 QDateTime effectiveDate = mixup.dateHeader();
139
140 if (effectiveDate > QDateTime::currentDateTime()) {
141 return;
142 }
143
144 if (d->gossip_timestamp.isValid() && effectiveDate <= d->gossip_timestamp) {
145 return;
146 }
147
148 const auto params = paramsFromAutocryptHeader(header);
149
150 if (d->addr.isEmpty()) {
151 d->addr = params.value("addr");
152 } else if (d->addr != params.value("addr")) {
153 return;
154 }
155
156 d->changed = true;
157 d->gossip_timestamp = effectiveDate;
158 d->gossip_key = params.value("keydata");
159 d->gossip_key.replace(' ', QByteArray());
160}
161
162QByteArray AutocryptRecipient::toJson(QJsonDocument::JsonFormat format) const
163{
164 const Q_D(AutocryptRecipient);
165 return d->toJson(format);
166}
167
168void AutocryptRecipient::fromJson(const QByteArray &json)
169{
170 Q_D(AutocryptRecipient);
171 return d->fromJson(json);
172}
173
174bool AutocryptRecipient::hasChanged() const
175{
176 const Q_D(AutocryptRecipient);
177 return d->changed;
178}
179
180void AutocryptRecipient::setChangedFlag(bool changed)
181{
182 Q_D(AutocryptRecipient);
183 d->changed = changed;
184}
185
186GpgME::Key gpgKey(const QByteArray &keydata)
187{
188 assert(QGpgME::openpgp()); // Make sure, that openpgp backend is loaded
189 auto context = GpgME::Context::create(GpgME::OpenPGP);
190 QGpgME::QByteArrayDataProvider dp(KCodecs::base64Decode(keydata));
191 GpgME::Data data(&dp);
192 const auto keys = data.toKeys();
193 if (keys.size() == 0) {
194 return {};
195 }
196 return keys[0];
197}
198
199GpgME::Key MessageCore::AutocryptRecipient::gpgKey() const
200{
201 const Q_D(AutocryptRecipient);
202 return ::gpgKey(d->keydata);
203}
204
205QByteArray MessageCore::AutocryptRecipient::gpgKeydata() const
206{
207 const Q_D(AutocryptRecipient);
208 return KCodecs::base64Decode(d->keydata);
209}
210
211GpgME::Key AutocryptRecipient::gossipKey() const
212{
213 const Q_D(AutocryptRecipient);
214 return ::gpgKey(d->gossip_key);
215}
216
217QByteArray MessageCore::AutocryptRecipient::gossipKeydata() const
218{
219 const Q_D(AutocryptRecipient);
220 return KCodecs::base64Decode(d->gossip_key);
221}
222
223QByteArray AutocryptRecipient::addr() const
224{
225 const Q_D(AutocryptRecipient);
226 return d->addr;
227}
228
229QByteArray AutocryptRecipient::bad_user_agent() const
230{
231 const Q_D(AutocryptRecipient);
232 return d->bad_user_agent;
233}
234
235QDateTime AutocryptRecipient::last_seen() const
236{
237 const Q_D(AutocryptRecipient);
238 return d->last_seen;
239}
240
241QDateTime AutocryptRecipient::autocrypt_timestamp() const
242{
243 const Q_D(AutocryptRecipient);
244 return d->autocrypt_timestamp;
245}
246
247QDateTime AutocryptRecipient::counting_since() const
248{
249 const Q_D(AutocryptRecipient);
250 return d->counting_since;
251}
252
253QDateTime AutocryptRecipient::gossip_timestamp() const
254{
255 const Q_D(AutocryptRecipient);
256 return d->gossip_timestamp;
257}
258
259int AutocryptRecipient::count_have_ach() const
260{
261 const Q_D(AutocryptRecipient);
262 return d->count_have_ach;
263}
264
265int AutocryptRecipient::count_no_ach() const
266{
267 const Q_D(AutocryptRecipient);
268 return d->count_no_ach;
269}
270
271bool AutocryptRecipient::prefer_encrypt() const
272{
273 const Q_D(AutocryptRecipient);
274 return d->prefer_encrypt;
275}
virtual QByteArray as7BitString(bool withHeaderType=true) const=0
char * toString(const EngineQuery &query)
KCODECS_EXPORT QByteArray base64Decode(QByteArrayView in)
int toInt(bool *ok, int base) const const
QDateTime currentDateTime()
QDateTime fromString(const QString &string, Qt::DateFormat format)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isObject() const const
QJsonObject object() const const
void setObject(const QJsonObject &object)
QByteArray toJson() const const
QJsonObject::iterator insert(const QString &key, const QJsonValue &value)
QJsonValue value(const QString &key) const const
QString toString() const const
QString fromLatin1(const char *str, int size)
QByteArray toLatin1() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:37:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.