Messagelib

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

KDE's Doxygen guidelines are available online.