File indexing completed on 2025-03-09 04:54:31
0001 /* 0002 SPDX-FileCopyrightText: 2019-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "dmarcinfo.h" 0008 #include "messageviewer_dkimcheckerdebug.h" 0009 0010 using namespace MessageViewer; 0011 DMARCInfo::DMARCInfo() = default; 0012 0013 bool DMARCInfo::parseDMARC(const QString &key) 0014 { 0015 if (key.isEmpty()) { 0016 qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Error: key empty"; 0017 return false; 0018 } 0019 QString cleanKey = key; 0020 cleanKey.replace(QLatin1StringView("; "), QLatin1StringView(";")); 0021 const QStringList items = cleanKey.split(QLatin1Char(';'), Qt::SkipEmptyParts); 0022 for (int i = 0; i < items.count(); ++i) { 0023 const QString elem = items.at(i).trimmed(); 0024 if (elem.startsWith(QLatin1StringView("v="))) { 0025 // v: Version (plain-text; REQUIRED). Identifies the record retrieved 0026 // as a DMARC record. It MUST have the value of "DMARC1". The value 0027 // of this tag MUST match precisely; if it does not or it is absent, 0028 // the entire retrieved record MUST be ignored. It MUST be the first 0029 // tag in the list. 0030 mVersion = elem.right(elem.length() - 2); 0031 } else if (elem.startsWith(QLatin1StringView("r="))) { 0032 // adkim: (plain-text; OPTIONAL; default is "r".) Indicates whether 0033 // strict or relaxed DKIM Identifier Alignment mode is required by 0034 // the Domain Owner. See Section 3.1.1 for details. Valid values 0035 // are as follows: 0036 // r: relaxed mode 0037 // s: strict mode 0038 mAdkim = elem.right(elem.length() - 2); 0039 } else if (elem.startsWith(QLatin1StringView("p="))) { 0040 // p: Requested Mail Receiver policy (plain-text; REQUIRED for policy 0041 // records). Indicates the policy to be enacted by the Receiver at 0042 // the request of the Domain Owner. Policy applies to the domain 0043 // queried and to subdomains, unless subdomain policy is explicitly 0044 // described using the "sp" tag. This tag is mandatory for policy 0045 // records only, but not for third-party reporting records (see 0046 // Section 7.1). Possible values are as follows: 0047 0048 // none: The Domain Owner requests no specific action be taken 0049 // regarding delivery of messages. 0050 0051 // quarantine: The Domain Owner wishes to have email that fails the 0052 // DMARC mechanism check be treated by Mail Receivers as 0053 // suspicious. Depending on the capabilities of the Mail 0054 // Receiver, this can mean "place into spam folder", "scrutinize 0055 // with additional intensity", and/or "flag as suspicious". 0056 0057 // reject: The Domain Owner wishes for Mail Receivers to reject 0058 // email that fails the DMARC mechanism check. Rejection SHOULD 0059 // occur during the SMTP transaction. See Section 10.3 for some 0060 // discussion of SMTP rejection methods and their implications. 0061 mPolicy = elem.right(elem.length() - 2); 0062 } else if (elem.startsWith(QLatin1StringView("ptc="))) { 0063 // pct: (plain-text integer between 0 and 100, inclusive; OPTIONAL; 0064 // default is 100). Percentage of messages from the Domain Owner's 0065 // mail stream to which the DMARC policy is to be applied. However, 0066 // this MUST NOT be applied to the DMARC-generated reports, all of 0067 // which must be sent and received unhindered. The purpose of the 0068 // "pct" tag is to allow Domain Owners to enact a slow rollout 0069 // enforcement of the DMARC mechanism. The prospect of "all or 0070 // nothing" is recognized as preventing many organizations from 0071 // experimenting with strong authentication-based mechanisms. See 0072 // Section 6.6.4 for details. Note that random selection based on 0073 // this percentage, such as the following pseudocode, is adequate: 0074 0075 // if (random mod 100) < pct then 0076 // selected = true 0077 // else 0078 // selected = false 0079 // TODO verify if it's a percentage 0080 mPercentage = QStringView(elem).right(elem.length() - 4).toInt(); 0081 } else if (elem.startsWith(QLatin1StringView("sp="))) { 0082 // sp: Requested Mail Receiver policy for all subdomains (plain-text; 0083 // OPTIONAL). Indicates the policy to be enacted by the Receiver at 0084 // the request of the Domain Owner. It applies only to subdomains of 0085 // the domain queried and not to the domain itself. Its syntax is 0086 // identical to that of the "p" tag defined above. If absent, the 0087 // policy specified by the "p" tag MUST be applied for subdomains. 0088 // Note that "sp" will be ignored for DMARC records published on 0089 // subdomains of Organizational Domains due to the effect of the 0090 // DMARC policy discovery mechanism described in Section 6.6.3. 0091 mSubDomainPolicy = elem.right(elem.length() - 3); 0092 } 0093 } 0094 if (mAdkim.isEmpty() && mVersion == QLatin1StringView("DMARC1")) { 0095 mAdkim = QLatin1Char('r'); 0096 } 0097 0098 return true; 0099 } 0100 0101 QString DMARCInfo::version() const 0102 { 0103 return mVersion; 0104 } 0105 0106 void DMARCInfo::setVersion(const QString &version) 0107 { 0108 mVersion = version; 0109 } 0110 0111 QString DMARCInfo::adkim() const 0112 { 0113 return mAdkim; 0114 } 0115 0116 void DMARCInfo::setAdkim(const QString &adkim) 0117 { 0118 mAdkim = adkim; 0119 } 0120 0121 QString DMARCInfo::policy() const 0122 { 0123 return mPolicy; 0124 } 0125 0126 void DMARCInfo::setPolicy(const QString &policy) 0127 { 0128 mPolicy = policy; 0129 } 0130 0131 int DMARCInfo::percentage() const 0132 { 0133 return mPercentage; 0134 } 0135 0136 void DMARCInfo::setPercentage(int percentage) 0137 { 0138 mPercentage = percentage; 0139 } 0140 0141 QString DMARCInfo::subDomainPolicy() const 0142 { 0143 return mSubDomainPolicy; 0144 } 0145 0146 void DMARCInfo::setSubDomainPolicy(const QString &subDomainPolicy) 0147 { 0148 mSubDomainPolicy = subDomainPolicy; 0149 } 0150 0151 bool DMARCInfo::operator==(const DMARCInfo &other) const 0152 { 0153 return mVersion == other.version() && mAdkim == other.adkim() && mPolicy == other.policy() && mSubDomainPolicy == other.subDomainPolicy() 0154 && mPercentage == other.percentage(); 0155 } 0156 0157 QDebug operator<<(QDebug d, const DMARCInfo &t) 0158 { 0159 d << " mVersion " << t.version(); 0160 d << " mAdkim " << t.adkim(); 0161 d << " mPolicy " << t.policy(); 0162 d << " mSubDomainPolicy " << t.subDomainPolicy(); 0163 d << " mPercentage " << t.percentage(); 0164 return d; 0165 }