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 #include <KCodecs>
12 #include <QGpgME/DataProvider>
13 #include <QGpgME/Protocol>
14 #include <QJsonObject>
15 #include <gpgme++/data.h>
16 
17 using namespace MessageCore;
18 
19 AutocryptRecipientPrivate::AutocryptRecipientPrivate() = default;
20 
21 QByteArray 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 
48 void 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 
89 AutocryptRecipient::AutocryptRecipient()
90  : d_ptr(new AutocryptRecipientPrivate())
91 {
92 }
93 
94 void 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 
135 void 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 
162 QByteArray AutocryptRecipient::toJson(QJsonDocument::JsonFormat format) const
163 {
164  const Q_D(AutocryptRecipient);
165  return d->toJson(format);
166 }
167 
168 void AutocryptRecipient::fromJson(const QByteArray &json)
169 {
170  Q_D(AutocryptRecipient);
171  return d->fromJson(json);
172 }
173 
174 bool AutocryptRecipient::hasChanged() const
175 {
176  const Q_D(AutocryptRecipient);
177  return d->changed;
178 }
179 
180 void AutocryptRecipient::setChangedFlag(bool changed)
181 {
182  Q_D(AutocryptRecipient);
183  d->changed = changed;
184 }
185 
186 GpgME::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  auto keys = data.toKeys();
193  if (keys.size() == 0) {
194  return {};
195  }
196  return keys[0];
197 }
198 
199 GpgME::Key MessageCore::AutocryptRecipient::gpgKey() const
200 {
201  const Q_D(AutocryptRecipient);
202  return ::gpgKey(d->keydata);
203 }
204 
205 QByteArray MessageCore::AutocryptRecipient::gpgKeydata() const
206 {
207  const Q_D(AutocryptRecipient);
208  return KCodecs::base64Decode(d->keydata);
209 }
210 
211 GpgME::Key AutocryptRecipient::gossipKey() const
212 {
213  const Q_D(AutocryptRecipient);
214  return ::gpgKey(d->gossip_key);
215 }
216 
217 QByteArray MessageCore::AutocryptRecipient::gossipKeydata() const
218 {
219  const Q_D(AutocryptRecipient);
220  return KCodecs::base64Decode(d->gossip_key);
221 }
222 
223 QByteArray AutocryptRecipient::addr() const
224 {
225  const Q_D(AutocryptRecipient);
226  return d->addr;
227 }
228 
229 QByteArray AutocryptRecipient::bad_user_agent() const
230 {
231  const Q_D(AutocryptRecipient);
232  return d->bad_user_agent;
233 }
234 
235 QDateTime AutocryptRecipient::last_seen() const
236 {
237  const Q_D(AutocryptRecipient);
238  return d->last_seen;
239 }
240 
241 QDateTime AutocryptRecipient::autocrypt_timestamp() const
242 {
243  const Q_D(AutocryptRecipient);
244  return d->autocrypt_timestamp;
245 }
246 
247 QDateTime AutocryptRecipient::counting_since() const
248 {
249  const Q_D(AutocryptRecipient);
250  return d->counting_since;
251 }
252 
253 QDateTime AutocryptRecipient::gossip_timestamp() const
254 {
255  const Q_D(AutocryptRecipient);
256  return d->gossip_timestamp;
257 }
258 
259 int AutocryptRecipient::count_have_ach() const
260 {
261  const Q_D(AutocryptRecipient);
262  return d->count_have_ach;
263 }
264 
265 int AutocryptRecipient::count_no_ach() const
266 {
267  const Q_D(AutocryptRecipient);
268  return d->count_no_ach;
269 }
270 
271 bool AutocryptRecipient::prefer_encrypt() const
272 {
273  const Q_D(AutocryptRecipient);
274  return d->prefer_encrypt;
275 }
QJsonObject object() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QDateTime currentDateTime()
QString toString() const const
QByteArray toLatin1() const const
QJsonObject::iterator insert(const QString &key, const QJsonValue &value)
char * toString(const T &value)
QJsonValue value(const QString &key) const const
KCODECS_EXPORT QByteArray base64Decode(const QByteArray &in)
QDateTime fromString(const QString &string, Qt::DateFormat format)
bool isObject() const const
int toInt(bool *ok, int base) const const
QString fromLatin1(const char *str, int size)
QByteArray toJson() const const
void setObject(const QJsonObject &object)
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Mar 27 2023 04:08:16 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.