Messagelib

dmarcpolicyjob.cpp
1/*
2 SPDX-FileCopyrightText: 2019-2024 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "dmarcpolicyjob.h"
8#include "dkimutil.h"
9#include "dmarcinfo.h"
10#include "dmarcrecordjob.h"
11#include "messageviewer_dkimcheckerdebug.h"
12using namespace MessageViewer;
13
14DMARCPolicyJob::DMARCPolicyJob(QObject *parent)
15 : QObject(parent)
16{
17}
18
19DMARCPolicyJob::~DMARCPolicyJob() = default;
20
21bool DMARCPolicyJob::canStart() const
22{
23 return !mEmailAddress.isEmpty();
24}
25
26bool DMARCPolicyJob::start()
27{
28 if (!canStart()) {
29 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << " Impossible to start DMARCPolicyJob" << mEmailAddress;
30 Q_EMIT result({}, mEmailAddress);
32 return false;
33 }
34
35 auto job = new DMARCRecordJob(this);
36 job->setDomainName(emailDomain());
37 connect(job, &MessageViewer::DMARCRecordJob::success, this, &DMARCPolicyJob::slotCheckDomain);
38 connect(job, &MessageViewer::DMARCRecordJob::error, this, [this](const QString &err, const QString &domainName) {
39 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "error: " << err << " domain " << domainName;
40 // Verify subdomain
41 checkSubDomain(domainName);
42 });
43 if (!job->start()) {
44 Q_EMIT result({}, mEmailAddress);
46 return false;
47 }
48 return true;
49}
50
51QByteArray DMARCPolicyJob::generateDMARCFromList(const QList<QByteArray> &lst) const
52{
54 if (lst.count() != 1) {
55 for (const QByteArray &b : lst) {
56 ba += b;
57 }
58 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "DMARCPolicyJob Key result has more that 1 element" << lst;
59 } else {
60 ba = lst.at(0);
61 }
62 return ba;
63}
64
65void DMARCPolicyJob::slotCheckSubDomain(const QList<QByteArray> &lst, const QString &domainName)
66{
67 const QByteArray ba = generateDMARCFromList(lst);
68 DMARCInfo info;
69 if (info.parseDMARC(QString::fromLocal8Bit(ba))) {
70 if ((info.version() != QLatin1StringView("DMARC1")) || info.policy().isEmpty() || (info.percentage() > 100 || info.percentage() < 0)) {
71 Q_EMIT result({}, mEmailAddress);
73 return;
74 } else {
75 DMARCPolicyJob::DMARCResult val;
76 val.mAdkim = info.adkim();
77 val.mPercentage = info.percentage();
78 val.mPolicy = info.subDomainPolicy().isEmpty() ? info.policy() : info.subDomainPolicy();
79 // TODO verify it !
80 val.mDomain = domainName;
81 val.mSource = domainName;
82 Q_EMIT result(val, mEmailAddress);
84 return;
85 }
86 }
87 Q_EMIT result({}, mEmailAddress);
88}
89
90void DMARCPolicyJob::checkSubDomain(const QString &domainName)
91{
92 const QString subDomain = emailSubDomain(domainName);
93 if (subDomain != domainName) {
94 auto job = new DMARCRecordJob(this);
95 job->setDomainName(subDomain);
96 connect(job, &MessageViewer::DMARCRecordJob::success, this, &DMARCPolicyJob::slotCheckSubDomain);
97 connect(job, &MessageViewer::DMARCRecordJob::error, this, [this](const QString &err, const QString &domainName) {
98 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "error: " << err << " domain " << domainName;
99 Q_EMIT result({}, mEmailAddress);
100 deleteLater();
101 });
102 if (!job->start()) {
103 Q_EMIT result({}, mEmailAddress);
104 deleteLater();
105 return;
106 }
107 } else {
108 // Invalid
109 Q_EMIT result({}, mEmailAddress);
110 deleteLater();
111 return;
112 }
113}
114
115void DMARCPolicyJob::slotCheckDomain(const QList<QByteArray> &lst, const QString &domainName)
116{
117 const QByteArray ba = generateDMARCFromList(lst);
118 DMARCInfo info;
119 if (info.parseDMARC(QString::fromLocal8Bit(ba))) {
120 if ((info.version() != QLatin1StringView("DMARC1")) || info.policy().isEmpty()
121 || (info.percentage() != -1 && (info.percentage() > 100 || info.percentage() < 0))) {
122 // Invalid
123 // Check subdomain
124 checkSubDomain(domainName);
125 } else {
126 DMARCPolicyJob::DMARCResult val;
127 val.mAdkim = info.adkim();
128 val.mPercentage = info.percentage();
129 val.mPolicy = info.policy();
130 val.mDomain = domainName;
131 val.mSource = domainName;
132 Q_EMIT result(val, mEmailAddress);
133 deleteLater();
134 return;
135 }
136 } else {
137 // Check subdomain
138 checkSubDomain(domainName);
139 }
140}
141
142QString DMARCPolicyJob::emailDomain() const
143{
144 return MessageViewer::DKIMUtil::emailDomain(mEmailAddress);
145}
146
147QString DMARCPolicyJob::emailSubDomain(const QString &domainName) const
148{
149 return MessageViewer::DKIMUtil::emailSubDomain(domainName);
150}
151
152QString DMARCPolicyJob::emailAddress() const
153{
154 return mEmailAddress;
155}
156
157void DMARCPolicyJob::setEmailAddress(const QString &emailAddress)
158{
159 mEmailAddress = emailAddress;
160}
161
162#include "moc_dmarcpolicyjob.cpp"
The DMARCInfo class.
Definition dmarcinfo.h:18
const T & at(int i) const const
int count(const T &value) const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void deleteLater()
T qobject_cast(QObject *object)
QString fromLocal8Bit(const char *str, int size)
bool isEmpty() const const
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.