Messagelib

dkiminfo.cpp
1/*
2 SPDX-FileCopyrightText: 2018-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "dkiminfo.h"
8#include "dkimutil.h"
9#include "messageviewer_dkimcheckerdebug.h"
10
11using namespace MessageViewer;
12
13DKIMInfo::DKIMInfo() = default;
14
15bool DKIMInfo::parseDKIM(const QString &header)
16{
17 if (header.isEmpty()) {
18 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Error: trying to parse empty header";
19 return false;
20 }
21 QString newHeaders = header;
22 newHeaders.replace(QLatin1StringView("; "), QLatin1StringView(";"));
23 const QStringList items = newHeaders.split(QLatin1Char(';'), Qt::SkipEmptyParts);
24 bool foundCanonizations = false;
25 for (int i = 0; i < items.count(); ++i) {
26 const QString elem = items.at(i).trimmed();
27 if (elem.startsWith(QLatin1StringView("v="))) {
28 mVersion = QStringView(elem).right(elem.length() - 2).toInt();
29 if (mVersion != 1) {
30 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Version is not correct " << mVersion;
31 }
32 } else if (elem.startsWith(QLatin1StringView("a="))) {
33 // Parse it as "algorithm.signature-algorithm.hash
34 parseAlgorithm(elem.right(elem.length() - 2));
35 } else if (elem.startsWith(QLatin1StringView("t="))) {
36 mSignatureTimeStamp = elem.right(elem.length() - 2).toLong();
37 } else if (elem.startsWith(QLatin1StringView("c="))) {
38 // Parse header/body canonicalization (example c=relaxed/simple) only relaxed and simple.
39 parseCanonicalization(elem.right(elem.length() - 2));
40 foundCanonizations = true;
41 } else if (elem.startsWith(QLatin1StringView("bh="))) {
42 mBodyHash = elem.right(elem.length() - 3).remove(QLatin1Char(' '));
43 } else if (elem.startsWith(QLatin1StringView("l="))) {
44 mBodyLengthCount = QStringView(elem).right(elem.length() - 2).toInt();
45 } else if (elem.startsWith(QLatin1StringView("i="))) {
46 mAgentOrUserIdentifier = elem.right(elem.length() - 2);
47 } else if (elem.startsWith(QLatin1StringView("q="))) {
48 mQuery = elem.right(elem.length() - 2);
49 if (mQuery != QLatin1StringView("dns/txt")) {
50 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Query is not correct and not supported " << mQuery;
51 }
52 } else if (elem.startsWith(QLatin1StringView("d="))) {
53 mDomain = elem.right(elem.length() - 2).trimmed();
54 } else if (elem.startsWith(QLatin1StringView("s="))) {
55 mSelector = elem.right(elem.length() - 2).trimmed();
56 } else if (elem.startsWith(QLatin1StringView("b="))) {
57 mSignature = elem.right(elem.length() - 2);
58 } else if (elem.startsWith(QLatin1StringView("h="))) {
59 const QString str = MessageViewer::DKIMUtil::cleanString(elem.right(elem.length() - 2));
60 mListSignedHeader = str.split(QLatin1Char(':'));
61 } else if (elem.startsWith(QLatin1StringView("x="))) {
62 mExpireTime = elem.right(elem.length() - 2).toLong();
63 } else if (elem.startsWith(QLatin1StringView("z="))) {
64 mCopiedHeaderField = elem.right(elem.length() - 2).split(QLatin1Char(':'));
65 } else {
66 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Unknown element type" << elem << " : items : " << items;
67 }
68 }
69 if (!foundCanonizations) { // Default
70 mHeaderCanonization = Simple;
71 mBodyCanonization = Simple;
72 }
73 if (mVersion == -1) {
74 mVersion = 1;
75 }
76 if (mQuery.isEmpty()) {
77 mQuery = QStringLiteral("dns/txt");
78 }
79 if (mAgentOrUserIdentifier.isEmpty()) {
80 mAgentOrUserIdentifier = QLatin1Char('@') + mDomain;
81 mIDomain = mDomain;
82 } else {
83 const QStringList lst = mAgentOrUserIdentifier.split(QLatin1Char('@'));
84 if (lst.count() == 2) {
85 if (mAgentOrUserIdentifier.isEmpty()) {
86 mAgentOrUserIdentifier = QLatin1Char('@') + mDomain;
87 }
88 mIDomain = lst.at(1);
89 }
90 }
91 return true;
92}
93
94void DKIMInfo::parseAlgorithm(const QString &str)
95{
96 // currently only "rsa-sha1" or "rsa-sha256"
97 const QStringList lst = str.split(QLatin1Char('-'));
98 if (lst.count() != 2) {
99 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "algorithm is invalid " << str;
100 // Error
101 } else {
102 mSigningAlgorithm = lst.at(0);
103 const QString hashStr = lst.at(1);
104 if (hashStr == QLatin1StringView("sha1")) {
105 mHashingAlgorithm = HashingAlgorithmType::Sha1;
106 } else if (hashStr == QLatin1StringView("sha256")) {
107 mHashingAlgorithm = HashingAlgorithmType::Sha256;
108 } else {
109 mHashingAlgorithm = HashingAlgorithmType::Unknown;
110 }
111 }
112}
113
114QString DKIMInfo::iDomain() const
115{
116 return mIDomain;
117}
118
119void DKIMInfo::setIDomain(const QString &iDomain)
120{
121 mIDomain = iDomain;
122}
123
124void DKIMInfo::parseCanonicalization(const QString &str)
125{
126 if (!str.isEmpty()) {
127 const QList<QStringView> canonicalization = QStringView(str).split(QLatin1Char('/'));
128 // qDebug() << " canonicalization "<< canonicalization;
129 if (canonicalization.count() >= 1) {
130 if (canonicalization.at(0) == QLatin1StringView("relaxed")) {
131 mHeaderCanonization = DKIMInfo::Relaxed;
132 } else if (canonicalization.at(0) == QLatin1StringView("simple")) {
133 mHeaderCanonization = DKIMInfo::Simple;
134 } else {
135 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "canonicalization for header unknown " << canonicalization.at(0);
136 mHeaderCanonization = DKIMInfo::Unknown;
137 return;
138 }
139 if (canonicalization.count() == 1) {
140 mBodyCanonization = DKIMInfo::Simple;
141 } else if (canonicalization.count() == 2) {
142 if (canonicalization.at(1) == QLatin1StringView("relaxed")) {
143 mBodyCanonization = DKIMInfo::Relaxed;
144 } else if (canonicalization.at(1) == QLatin1StringView("simple")) {
145 mBodyCanonization = DKIMInfo::Simple;
146 } else {
147 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "canonicalization for body unknown " << canonicalization.at(1);
148 mBodyCanonization = DKIMInfo::Unknown;
149 return;
150 }
151 } else {
152 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Problem during parsing canonicalization " << str;
153 mHeaderCanonization = DKIMInfo::Unknown;
154 mBodyCanonization = DKIMInfo::Unknown;
155 }
156 }
157 }
158}
159
160QStringList DKIMInfo::copiedHeaderField() const
161{
162 return mCopiedHeaderField;
163}
164
165void DKIMInfo::setCopiedHeaderField(const QStringList &copiedHeaderField)
166{
167 mCopiedHeaderField = copiedHeaderField;
168}
169
170DKIMInfo::CanonicalizationType DKIMInfo::bodyCanonization() const
171{
172 return mBodyCanonization;
173}
174
175void DKIMInfo::setBodyCanonization(CanonicalizationType bodyCanonization)
176{
177 mBodyCanonization = bodyCanonization;
178}
179
180bool DKIMInfo::operator==(const DKIMInfo &other) const
181{
182 return mVersion == other.version() && mHashingAlgorithm == other.hashingAlgorithm() && mSigningAlgorithm == other.signingAlgorithm()
183 && mDomain == other.domain() && mSelector == other.selector() && mBodyHash == other.bodyHash() && mSignatureTimeStamp == other.signatureTimeStamp()
184 && mExpireTime == other.expireTime() && mQuery == other.query() && mSignature == other.signature()
185 && mAgentOrUserIdentifier == other.agentOrUserIdentifier() && mBodyLengthCount == other.bodyLengthCount()
186 && mListSignedHeader == other.listSignedHeader() && mHeaderCanonization == other.headerCanonization() && mBodyCanonization == other.bodyCanonization()
187 && mIDomain == other.iDomain();
188}
189
190DKIMInfo::CanonicalizationType DKIMInfo::headerCanonization() const
191{
192 return mHeaderCanonization;
193}
194
195void DKIMInfo::setHeaderCanonization(CanonicalizationType headerCanonization)
196{
197 mHeaderCanonization = headerCanonization;
198}
199
200int DKIMInfo::version() const
201{
202 return mVersion;
203}
204
205void DKIMInfo::setVersion(int version)
206{
207 mVersion = version;
208}
209
210DKIMInfo::HashingAlgorithmType DKIMInfo::hashingAlgorithm() const
211{
212 return mHashingAlgorithm;
213}
214
215void DKIMInfo::setHashingAlgorithm(DKIMInfo::HashingAlgorithmType hashingAlgorithm)
216{
217 mHashingAlgorithm = hashingAlgorithm;
218}
219
220QString DKIMInfo::domain() const
221{
222 return mDomain;
223}
224
225void DKIMInfo::setDomain(const QString &domain)
226{
227 mDomain = domain;
228}
229
230QString DKIMInfo::selector() const
231{
232 return mSelector;
233}
234
235void DKIMInfo::setSelector(const QString &selector)
236{
237 mSelector = selector;
238}
239
240QString DKIMInfo::bodyHash() const
241{
242 return mBodyHash;
243}
244
245void DKIMInfo::setBodyHash(const QString &bodyHash)
246{
247 mBodyHash = bodyHash;
248}
249
250bool DKIMInfo::isValid() const
251{
252 if (mBodyCanonization == DKIMInfo::Unknown || mHeaderCanonization == DKIMInfo::Unknown) {
253 return false;
254 }
255
256 return !mSelector.isEmpty() && !mDomain.isEmpty() && !mBodyHash.isEmpty()
257 && ((mHashingAlgorithm == HashingAlgorithmType::Sha1) || mHashingAlgorithm == HashingAlgorithmType::Sha256);
258}
259
260QStringList DKIMInfo::listSignedHeader() const
261{
262 return mListSignedHeader;
263}
264
265void DKIMInfo::setListSignedHeader(const QStringList &listSignedHeader)
266{
267 mListSignedHeader = listSignedHeader;
268}
269
270QString DKIMInfo::signingAlgorithm() const
271{
272 return mSigningAlgorithm;
273}
274
275void DKIMInfo::setSigningAlgorithm(const QString &signingAlgorithm)
276{
277 mSigningAlgorithm = signingAlgorithm;
278}
279
280qint64 DKIMInfo::signatureTimeStamp() const
281{
282 return mSignatureTimeStamp;
283}
284
285void DKIMInfo::setSignatureTimeStamp(qint64 signatureTimeStamp)
286{
287 mSignatureTimeStamp = signatureTimeStamp;
288}
289
290QString DKIMInfo::query() const
291{
292 return mQuery;
293}
294
295void DKIMInfo::setQuery(const QString &query)
296{
297 mQuery = query;
298}
299
300qint64 DKIMInfo::expireTime() const
301{
302 return mExpireTime;
303}
304
305void DKIMInfo::setExpireTime(qint64 expireTime)
306{
307 mExpireTime = expireTime;
308}
309
310QString DKIMInfo::signature() const
311{
312 return mSignature;
313}
314
315void DKIMInfo::setSignature(const QString &signature)
316{
317 mSignature = signature;
318}
319
320QString DKIMInfo::agentOrUserIdentifier() const
321{
322 return mAgentOrUserIdentifier;
323}
324
325void DKIMInfo::setAgentOrUserIdentifier(const QString &userAgent)
326{
327 mAgentOrUserIdentifier = userAgent;
328}
329
330int DKIMInfo::bodyLengthCount() const
331{
332 return mBodyLengthCount;
333}
334
335void DKIMInfo::setBodyLengthCount(int bodyLengthCount)
336{
337 mBodyLengthCount = bodyLengthCount;
338}
339
340QDebug operator<<(QDebug d, const DKIMInfo &t)
341{
342 d << "mVersion " << t.version();
343 d << "mHashingAlgorithm " << t.hashingAlgorithm();
344 d << "mSigningAlgorithm " << t.signingAlgorithm();
345 d << "mDomain " << t.domain();
346 d << "mSelector " << t.selector();
347 d << "mBodyHash " << t.bodyHash();
348 d << "mSignatureTimeStamp " << t.signatureTimeStamp();
349 d << "mExpireTime " << t.expireTime();
350 d << "mQuery " << t.query();
351 d << "mSignature " << t.signature();
352 d << "mAgentOrUserIdentifier " << t.agentOrUserIdentifier();
353 d << "mBodyLengthCount " << t.bodyLengthCount();
354 d << "mListSignedHeader " << t.listSignedHeader();
355 d << "mHeaderCanonization " << t.headerCanonization();
356 d << "mBodyCanonization " << t.bodyCanonization();
357 d << "mIdomain " << t.iDomain();
358 return d;
359}
360
361#include "moc_dkiminfo.cpp"
The DKIMInfo class.
Definition dkiminfo.h:20
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KDB_EXPORT KDbVersionInfo version()
QDebug operator<<(QDebug dbg, const PerceptualColor::LchaDouble &value)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
qsizetype length() const const
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString right(qsizetype n) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
long toLong(bool *ok, int base) const const
QString trimmed() const const
QStringView right(qsizetype length) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
SkipEmptyParts
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:12:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.