File indexing completed on 2025-03-09 04:54:29

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 "dkimkeyrecord.h"
0008 #include "messageviewer_dkimcheckerdebug.h"
0009 
0010 using namespace MessageViewer;
0011 
0012 DKIMKeyRecord::DKIMKeyRecord() = default;
0013 
0014 bool DKIMKeyRecord::parseKey(const QString &key)
0015 {
0016     qDebug() << " key " << key;
0017     QString newKey = key;
0018     if (newKey.isEmpty()) {
0019         qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "Error: trying to parse empty key";
0020         return false;
0021     }
0022     newKey.replace(QLatin1StringView("; "), QLatin1StringView(";"));
0023     const QStringList items = newKey.split(QLatin1Char(';'));
0024     for (int i = 0; i < items.count(); ++i) {
0025         const QString elem = items.at(i).trimmed();
0026         if (elem.startsWith(QLatin1StringView("v="))) {
0027             mVersion = elem.right(elem.length() - 2);
0028         } else if (elem.startsWith(QLatin1StringView("h="))) {
0029             // Parse multi array.
0030             mHashAlgorithm = elem.right(elem.length() - 2).split(QLatin1Char(':'));
0031         } else if (elem.startsWith(QLatin1StringView("k="))) { // Key type (rsa by default)
0032             mKeyType = elem.right(elem.length() - 2);
0033         } else if (elem.startsWith(QLatin1StringView("n="))) { // Notes (optional empty by default)
0034             mNote = elem.right(elem.length() - 2);
0035         } else if (elem.startsWith(QLatin1StringView("p="))) { // Public key
0036             mPublicKey = elem.right(elem.length() - 2).remove(QLatin1Char(' '));
0037         } else if (elem.startsWith(QLatin1StringView("s="))) { // Service Default is "*"
0038             // Service Type (plain-text; OPTIONAL; default is "*").  A colon-
0039             // separated list of service types to which this record applies.
0040             // Verifiers for a given service type MUST ignore this record if the
0041             // appropriate type is not listed.  Unrecognized service types MUST
0042             // be ignored.  Currently defined service types are as follows:
0043             const QStringList lst = elem.right(elem.length() - 2).split(QLatin1Char(':'));
0044             for (const QString &service : lst) {
0045                 if (service == QLatin1Char('*') || service == QLatin1StringView("email")) {
0046                     mService = service;
0047                 }
0048             }
0049         } else if (elem.startsWith(QLatin1StringView("t="))) { // Flag
0050             //            t= Flags, represented as a colon-separated list of names (plain-
0051             //                  text; OPTIONAL, default is no flags set).  Unrecognized flags MUST
0052             //                  be ignored.  The defined flags are as follows:
0053 
0054             //                  y  This domain is testing DKIM.  Verifiers MUST NOT treat messages
0055             //                     from Signers in testing mode differently from unsigned email,
0056             //                     even should the signature fail to verify.  Verifiers MAY wish
0057             //                     to track testing mode results to assist the Signer.
0058 
0059             //                  s  Any DKIM-Signature header fields using the "i=" tag MUST have
0060             //                     the same domain value on the right-hand side of the "@" in the
0061             //                     "i=" tag and the value of the "d=" tag.  That is, the "i="
0062             //                     domain MUST NOT be a subdomain of "d=".  Use of this flag is
0063             //                     RECOMMENDED unless subdomaining is required.
0064             mFlags = elem.right(elem.length() - 2).split(QLatin1Char(':'));
0065         }
0066     }
0067     if (mVersion.isEmpty()) { // It's optional
0068         mVersion = QStringLiteral("DKIM1");
0069     }
0070     if (mKeyType.isEmpty()) { // Rsa by default
0071         mKeyType = QStringLiteral("rsa");
0072     }
0073     if (mService.isEmpty()) {
0074         mService = QLatin1Char('*');
0075     }
0076     return true;
0077 }
0078 
0079 QString DKIMKeyRecord::version() const
0080 {
0081     return mVersion;
0082 }
0083 
0084 void DKIMKeyRecord::setVersion(const QString &version)
0085 {
0086     mVersion = version;
0087 }
0088 
0089 QString DKIMKeyRecord::keyType() const
0090 {
0091     return mKeyType;
0092 }
0093 
0094 void DKIMKeyRecord::setKeyType(const QString &keyType)
0095 {
0096     mKeyType = keyType;
0097 }
0098 
0099 QString DKIMKeyRecord::note() const
0100 {
0101     return mNote;
0102 }
0103 
0104 void DKIMKeyRecord::setNote(const QString &note)
0105 {
0106     mNote = note;
0107 }
0108 
0109 QString DKIMKeyRecord::publicKey() const
0110 {
0111     return mPublicKey;
0112 }
0113 
0114 void DKIMKeyRecord::setPublicKey(const QString &publicKey)
0115 {
0116     mPublicKey = publicKey;
0117 }
0118 
0119 QString DKIMKeyRecord::service() const
0120 {
0121     return mService;
0122 }
0123 
0124 void DKIMKeyRecord::setService(const QString &service)
0125 {
0126     mService = service;
0127 }
0128 
0129 QStringList DKIMKeyRecord::flags() const
0130 {
0131     return mFlags;
0132 }
0133 
0134 void DKIMKeyRecord::setFlags(const QStringList &flags)
0135 {
0136     mFlags = flags;
0137 }
0138 
0139 bool DKIMKeyRecord::operator==(const DKIMKeyRecord &other) const
0140 {
0141     return mVersion == other.version() && mNote == other.note() && mPublicKey == other.publicKey() && mService == other.service()
0142         && mHashAlgorithm == other.hashAlgorithm() && mFlags == other.flags();
0143 }
0144 
0145 QStringList DKIMKeyRecord::hashAlgorithm() const
0146 {
0147     return mHashAlgorithm;
0148 }
0149 
0150 void DKIMKeyRecord::setHashAlgorithm(const QStringList &hashAlgorithm)
0151 {
0152     mHashAlgorithm = hashAlgorithm;
0153 }
0154 
0155 QDebug operator<<(QDebug d, const DKIMKeyRecord &t)
0156 {
0157     d << "mVersion " << t.version();
0158     d << "mKeyType " << t.keyType();
0159     d << "mNote " << t.note();
0160     d << "mPublicKey " << t.publicKey();
0161     d << "mService " << t.service();
0162     d << "mHashAlgorithm " << t.hashAlgorithm();
0163     d << "mFlags " << t.flags();
0164     return d;
0165 }