Messagelib

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

KDE's Doxygen guidelines are available online.