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
94AutocryptRecipient::~AutocryptRecipient() = default;
95
96void AutocryptRecipient::updateFromMessage(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
97{
98 Q_D(AutocryptRecipient);
99 QDateTime effectiveDate = mixup.dateHeader();
100
101 if (effectiveDate > QDateTime::currentDateTime()) {
102 return;
103 }
104
105 if (d->autocrypt_timestamp.isValid() && effectiveDate <= d->autocrypt_timestamp) {
106 return;
107 }
108
109 d->autocrypt_timestamp = effectiveDate;
110 d->changed = true;
111
112 if (!d->counting_since.isValid()) {
113 d->counting_since = effectiveDate;
114 d->count_have_ach = 0;
115 d->count_no_ach = 0;
116 }
117
118 if (header) {
119 const auto params = paramsFromAutocryptHeader(header);
120 if (d->addr.isEmpty()) {
121 d->addr = params.value("addr");
122 }
123 d->prefer_encrypt = params.contains("prefer-encrypt");
124 d->keydata = params.value("keydata");
125 d->keydata.replace(' ', QByteArray());
126
127 d->last_seen = effectiveDate;
128 d->count_have_ach += 1;
129 } else {
130 d->count_no_ach += 1;
131 if (mixup.hasMailHeader("User-Agent")) {
132 d->bad_user_agent = mixup.mailHeaderAsBase("User-Agent")->as7BitString(false);
133 }
134 }
135}
136
137void AutocryptRecipient::updateFromGossip(const HeaderMixupNodeHelper &mixup, const KMime::Headers::Base *header)
138{
139 Q_D(AutocryptRecipient);
140 QDateTime effectiveDate = mixup.dateHeader();
141
142 if (effectiveDate > QDateTime::currentDateTime()) {
143 return;
144 }
145
146 if (d->gossip_timestamp.isValid() && effectiveDate <= d->gossip_timestamp) {
147 return;
148 }
149
150 const auto params = paramsFromAutocryptHeader(header);
151
152 if (d->addr.isEmpty()) {
153 d->addr = params.value("addr");
154 } else if (d->addr != params.value("addr")) {
155 return;
156 }
157
158 d->changed = true;
159 d->gossip_timestamp = effectiveDate;
160 d->gossip_key = params.value("keydata");
161 d->gossip_key.replace(' ', QByteArray());
162}
163
164QByteArray AutocryptRecipient::toJson(QJsonDocument::JsonFormat format) const
165{
166 const Q_D(AutocryptRecipient);
167 return d->toJson(format);
168}
169
170void AutocryptRecipient::fromJson(const QByteArray &json)
171{
172 Q_D(AutocryptRecipient);
173 return d->fromJson(json);
174}
175
176bool AutocryptRecipient::hasChanged() const
177{
178 const Q_D(AutocryptRecipient);
179 return d->changed;
180}
181
182void AutocryptRecipient::setChangedFlag(bool changed)
183{
184 Q_D(AutocryptRecipient);
185 d->changed = changed;
186}
187
188GpgME::Key gpgKey(const QByteArray &keydata)
189{
190 assert(QGpgME::openpgp()); // Make sure, that openpgp backend is loaded
191 auto context = GpgME::Context::create(GpgME::OpenPGP);
192 QGpgME::QByteArrayDataProvider dp(KCodecs::base64Decode(keydata));
193 GpgME::Data data(&dp);
194 const auto keys = data.toKeys();
195 if (keys.size() == 0) {
196 return {};
197 }
198 return keys[0];
199}
200
201GpgME::Key MessageCore::AutocryptRecipient::gpgKey() const
202{
203 const Q_D(AutocryptRecipient);
204 return ::gpgKey(d->keydata);
205}
206
207QByteArray MessageCore::AutocryptRecipient::gpgKeydata() const
208{
209 const Q_D(AutocryptRecipient);
210 return KCodecs::base64Decode(d->keydata);
211}
212
213GpgME::Key AutocryptRecipient::gossipKey() const
214{
215 const Q_D(AutocryptRecipient);
216 return ::gpgKey(d->gossip_key);
217}
218
219QByteArray MessageCore::AutocryptRecipient::gossipKeydata() const
220{
221 const Q_D(AutocryptRecipient);
222 return KCodecs::base64Decode(d->gossip_key);
223}
224
225QByteArray AutocryptRecipient::addr() const
226{
227 const Q_D(AutocryptRecipient);
228 return d->addr;
229}
230
231QByteArray AutocryptRecipient::bad_user_agent() const
232{
233 const Q_D(AutocryptRecipient);
234 return d->bad_user_agent;
235}
236
237QDateTime AutocryptRecipient::last_seen() const
238{
239 const Q_D(AutocryptRecipient);
240 return d->last_seen;
241}
242
243QDateTime AutocryptRecipient::autocrypt_timestamp() const
244{
245 const Q_D(AutocryptRecipient);
246 return d->autocrypt_timestamp;
247}
248
249QDateTime AutocryptRecipient::counting_since() const
250{
251 const Q_D(AutocryptRecipient);
252 return d->counting_since;
253}
254
255QDateTime AutocryptRecipient::gossip_timestamp() const
256{
257 const Q_D(AutocryptRecipient);
258 return d->gossip_timestamp;
259}
260
261int AutocryptRecipient::count_have_ach() const
262{
263 const Q_D(AutocryptRecipient);
264 return d->count_have_ach;
265}
266
267int AutocryptRecipient::count_no_ach() const
268{
269 const Q_D(AutocryptRecipient);
270 return d->count_no_ach;
271}
272
273bool AutocryptRecipient::prefer_encrypt() const
274{
275 const Q_D(AutocryptRecipient);
276 return d->prefer_encrypt;
277}
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(QStringView string, QStringView format, QCalendar cal)
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isObject() const const
QJsonObject object() const const
void setObject(const QJsonObject &object)
QByteArray toJson(JsonFormat format) const const
iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
QString toString() const const
QString fromLatin1(QByteArrayView str)
QByteArray toLatin1() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:07:25 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.