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 "dkimwidgetinfo.h"
0008 #include "dkimmanager.h"
0009 #include "dkimutil.h"
0010 #include "messageviewer_dkimcheckerdebug.h"
0011 #include <KColorScheme>
0012 #include <KLocalizedString>
0013 
0014 #include <QHBoxLayout>
0015 #include <QLabel>
0016 
0017 using namespace MessageViewer;
0018 DKIMWidgetInfo::DKIMWidgetInfo(QWidget *parent)
0019     : QWidget(parent)
0020     , mLabel(new QLabel(this))
0021 {
0022     auto mainLayout = new QHBoxLayout(this);
0023     mainLayout->setObjectName(QLatin1StringView("mainLayout"));
0024     mainLayout->setContentsMargins({});
0025 
0026     mLabel->setAutoFillBackground(true);
0027     mLabel->setObjectName(QLatin1StringView("label"));
0028     mainLayout->addWidget(mLabel);
0029     connect(DKIMManager::self(), &DKIMManager::result, this, &DKIMWidgetInfo::setResult);
0030     connect(DKIMManager::self(), &DKIMManager::clearInfo, this, &DKIMWidgetInfo::clear);
0031     initColors();
0032 }
0033 
0034 DKIMWidgetInfo::~DKIMWidgetInfo() = default;
0035 
0036 void DKIMWidgetInfo::updatePalette()
0037 {
0038     initColors();
0039     updateInfo();
0040 }
0041 
0042 void DKIMWidgetInfo::initColors()
0043 {
0044     const KColorScheme colorScheme{QPalette::Active};
0045     mWarningColor = colorScheme.background(KColorScheme::NeutralBackground).color();
0046     mErrorColor = colorScheme.background(KColorScheme::NegativeBackground).color();
0047     mOkColor = colorScheme.background(KColorScheme::PositiveBackground).color();
0048     mDefaultColor = Qt::transparent; // colorScheme.background(KColorScheme::ActiveBackground).color();
0049 }
0050 
0051 MessageViewer::DKIMCheckSignatureJob::CheckSignatureResult DKIMWidgetInfo::result() const
0052 {
0053     return mResult;
0054 }
0055 
0056 Akonadi::Item::Id DKIMWidgetInfo::currentItemId() const
0057 {
0058     return mCurrentItemId;
0059 }
0060 
0061 void DKIMWidgetInfo::setCurrentItemId(Akonadi::Item::Id currentItemId)
0062 {
0063     mCurrentItemId = currentItemId;
0064 }
0065 
0066 void DKIMWidgetInfo::setResult(const DKIMCheckSignatureJob::CheckSignatureResult &checkResult, Akonadi::Item::Id id)
0067 {
0068     if (mCurrentItemId == id) {
0069         if (mResult != checkResult) {
0070             mResult = checkResult;
0071             updateInfo();
0072         }
0073     }
0074 }
0075 
0076 void DKIMWidgetInfo::clear()
0077 {
0078     mLabel->clear();
0079     mLabel->setToolTip(QString());
0080     QPalette pal = mLabel->palette();
0081     pal.setColor(backgroundRole(), mDefaultColor);
0082     mLabel->setPalette(pal);
0083     mCurrentItemId = -1;
0084     mResult = {};
0085 }
0086 
0087 void DKIMWidgetInfo::updateInfo()
0088 {
0089     QPalette pal = mLabel->palette();
0090     switch (mResult.status) {
0091     case DKIMCheckSignatureJob::DKIMStatus::Unknown:
0092         pal.setColor(backgroundRole(), mDefaultColor);
0093         mLabel->setPalette(pal);
0094         mLabel->setText(i18n("Unknown"));
0095         break;
0096     case DKIMCheckSignatureJob::DKIMStatus::Valid:
0097         if (mResult.sdid.isEmpty()) {
0098             qCWarning(MESSAGEVIEWER_DKIMCHECKER_LOG) << "mResult.sdid is empty. It's a bug";
0099         }
0100         mLabel->setText(i18n("DKIM: valid (signed by %1)", mResult.sdid));
0101         pal.setColor(backgroundRole(), (mResult.warning != DKIMCheckSignatureJob::DKIMWarning::Any) ? mWarningColor : mOkColor);
0102         mLabel->setPalette(pal);
0103         break;
0104     case DKIMCheckSignatureJob::DKIMStatus::Invalid:
0105         pal.setColor(backgroundRole(), mErrorColor);
0106         mLabel->setPalette(pal);
0107         mLabel->setText(i18n("DKIM: invalid"));
0108         break;
0109     case DKIMCheckSignatureJob::DKIMStatus::EmailNotSigned:
0110         mLabel->setText(i18n("DKIM: Not signed"));
0111         pal.setColor(backgroundRole(), mDefaultColor);
0112         mLabel->setPalette(pal);
0113         break;
0114     case DKIMCheckSignatureJob::DKIMStatus::NeedToBeSigned:
0115         mLabel->setText(i18n("DKIM: Should Be Signed by %1", mResult.sdid));
0116         pal.setColor(backgroundRole(), mErrorColor);
0117         mLabel->setPalette(pal);
0118         break;
0119     }
0120     updateToolTip();
0121 }
0122 
0123 void DKIMWidgetInfo::updateToolTip()
0124 {
0125     QString tooltip;
0126     if (mResult.status == DKIMCheckSignatureJob::DKIMStatus::Invalid) {
0127         switch (mResult.error) {
0128         case DKIMCheckSignatureJob::DKIMError::Any:
0129             break;
0130         case DKIMCheckSignatureJob::DKIMError::CorruptedBodyHash:
0131             tooltip = i18n("Body Hash was corrupted.");
0132             break;
0133         case DKIMCheckSignatureJob::DKIMError::DomainNotExist:
0134             tooltip = i18n("The domain doesn't exist.");
0135             break;
0136         case DKIMCheckSignatureJob::DKIMError::MissingFrom:
0137             tooltip = i18n("Missing header From.");
0138             break;
0139         case DKIMCheckSignatureJob::DKIMError::MissingSignature:
0140             tooltip = i18n("Missing signature.");
0141             break;
0142         case DKIMCheckSignatureJob::DKIMError::InvalidQueryMethod:
0143             tooltip = i18n("Invalid query method.");
0144             break;
0145         case DKIMCheckSignatureJob::DKIMError::InvalidHeaderCanonicalization:
0146             tooltip = i18n("Invalid header canonicalization.");
0147             break;
0148         case DKIMCheckSignatureJob::DKIMError::InvalidBodyCanonicalization:
0149             tooltip = i18n("Invalid body canonicalization.");
0150             break;
0151         case DKIMCheckSignatureJob::DKIMError::InvalidBodyHashAlgorithm:
0152             tooltip = i18n("Unknown Body Hash Algorithm.");
0153             break;
0154         case DKIMCheckSignatureJob::DKIMError::InvalidSignAlgorithm:
0155             tooltip = i18n("Signature algorithm is invalid.");
0156             break;
0157         case DKIMCheckSignatureJob::DKIMError::PublicKeyWasRevoked:
0158             tooltip = i18n("The public key was revoked.");
0159             break;
0160         case DKIMCheckSignatureJob::DKIMError::SignatureTooLarge:
0161             tooltip = i18n("Signature is too large.");
0162             break;
0163         case DKIMCheckSignatureJob::DKIMError::InsupportedHashAlgorithm:
0164             tooltip = i18n("Hash Algorithm is unsupported.");
0165             break;
0166         case DKIMCheckSignatureJob::DKIMError::PublicKeyTooSmall:
0167             tooltip = i18n("Public key is too small.");
0168             break;
0169         case DKIMCheckSignatureJob::DKIMError::ImpossibleToVerifySignature:
0170             tooltip = i18n("Impossible to verify signature.");
0171             break;
0172         case DKIMCheckSignatureJob::DKIMError::DomainI:
0173             tooltip = i18n("AUID must be in the same domain as SDID (s-flag set in key record).");
0174             break;
0175         case DKIMCheckSignatureJob::DKIMError::TestKeyMode:
0176             tooltip = i18n("The signing domain is only testing DKIM.");
0177             break;
0178         case DKIMCheckSignatureJob::DKIMError::ImpossibleToDownloadKey:
0179             tooltip = i18n("Impossible to download key.");
0180             break;
0181         case DKIMCheckSignatureJob::DKIMError::HashAlgorithmUnsafeSha1:
0182             tooltip = i18n("Hash Algorithm unsafe (sha1)");
0183             break;
0184         case DKIMCheckSignatureJob::DKIMError::IDomainError:
0185             tooltip = i18n("AUID is not in a subdomain of SDID");
0186             break;
0187         case DKIMCheckSignatureJob::DKIMError::PublicKeyConversionError:
0188             tooltip = i18n("Problem during converting public key");
0189             break;
0190         }
0191     }
0192 
0193     switch (mResult.warning) {
0194     case DKIMCheckSignatureJob::DKIMWarning::Any:
0195         break;
0196     case DKIMCheckSignatureJob::DKIMWarning::SignatureExpired:
0197         tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Signature expired");
0198         break;
0199     case DKIMCheckSignatureJob::DKIMWarning::SignatureCreatedInFuture:
0200         tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Signature created in the future");
0201         break;
0202     case DKIMCheckSignatureJob::DKIMWarning::SignatureTooSmall:
0203         tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Signature too small");
0204         break;
0205     case DKIMCheckSignatureJob::DKIMWarning::HashAlgorithmUnsafe:
0206         tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Hash Algorithm unsafe (sha1)");
0207         break;
0208     case DKIMCheckSignatureJob::DKIMWarning::PublicRsaKeyTooSmall:
0209         tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Public Key too small");
0210         break;
0211     }
0212 
0213     if (mResult.status != DKIMCheckSignatureJob::DKIMStatus::Invalid) {
0214         QStringList tooltipList;
0215         for (const DKIMCheckSignatureJob::DKIMCheckSignatureAuthenticationResult &result : std::as_const(mResult.listSignatureAuthenticationResult)) {
0216             switch (result.status) {
0217             case DKIMCheckSignatureJob::DKIMStatus::Unknown:
0218                 break;
0219             case DKIMCheckSignatureJob::DKIMStatus::Invalid:
0220                 switch (result.method) {
0221                 case DKIMCheckSignatureJob::AuthenticationMethod::Unknown: {
0222                     break;
0223                 }
0224                 case DKIMCheckSignatureJob::AuthenticationMethod::Spf:
0225                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkim:
0226                 case DKIMCheckSignatureJob::AuthenticationMethod::Dmarc:
0227                 case DKIMCheckSignatureJob::AuthenticationMethod::Auth:
0228                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkimatps: {
0229                     const QString str = i18nc("method name: info about it from parsing",
0230                                               "%1: %2",
0231                                               MessageViewer::DKIMUtil::convertAuthenticationMethodEnumToString(result.method),
0232                                               result.infoResult);
0233                     if (!tooltipList.contains(str)) {
0234                         tooltipList.append(str);
0235                     }
0236                     break;
0237                 }
0238                 }
0239                 break;
0240 
0241             case DKIMCheckSignatureJob::DKIMStatus::NeedToBeSigned:
0242                 break;
0243             case DKIMCheckSignatureJob::DKIMStatus::EmailNotSigned:
0244                 switch (result.method) {
0245                 case DKIMCheckSignatureJob::AuthenticationMethod::Unknown: {
0246                     break;
0247                 }
0248                 case DKIMCheckSignatureJob::AuthenticationMethod::Spf:
0249                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkim:
0250                 case DKIMCheckSignatureJob::AuthenticationMethod::Dmarc:
0251                 case DKIMCheckSignatureJob::AuthenticationMethod::Auth:
0252                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkimatps: {
0253                     const QString str = i18n("%1: None", MessageViewer::DKIMUtil::convertAuthenticationMethodEnumToString(result.method));
0254                     if (!tooltipList.contains(str)) {
0255                         tooltipList.append(str);
0256                     }
0257                     break;
0258                 }
0259                 }
0260                 break;
0261             case DKIMCheckSignatureJob::DKIMStatus::Valid:
0262                 switch (result.method) {
0263                 case DKIMCheckSignatureJob::AuthenticationMethod::Unknown: {
0264                     break;
0265                 }
0266                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkim: {
0267                     const QString str =
0268                         i18n("%1: Valid (Signed by %2)", MessageViewer::DKIMUtil::convertAuthenticationMethodEnumToString(result.method), result.sdid);
0269                     if (!tooltipList.contains(str)) {
0270                         tooltipList.append(str);
0271                     }
0272                     break;
0273                 }
0274                 case DKIMCheckSignatureJob::AuthenticationMethod::Spf: {
0275                     const QString str = i18nc("method name: info about it from parsing",
0276                                               "%1: %2",
0277                                               MessageViewer::DKIMUtil::convertAuthenticationMethodEnumToString(result.method),
0278                                               result.infoResult);
0279                     if (!tooltipList.contains(str)) {
0280                         tooltipList.append(str);
0281                     }
0282 
0283                     break;
0284                 }
0285                 case DKIMCheckSignatureJob::AuthenticationMethod::Auth:
0286                 case DKIMCheckSignatureJob::AuthenticationMethod::Dkimatps:
0287                 case DKIMCheckSignatureJob::AuthenticationMethod::Dmarc: {
0288                     const QString str = i18n("%1: Valid", MessageViewer::DKIMUtil::convertAuthenticationMethodEnumToString(result.method));
0289                     if (!tooltipList.contains(str)) {
0290                         tooltipList.append(str);
0291                     }
0292 
0293                     break;
0294                 }
0295                 }
0296                 break;
0297             }
0298         }
0299         if (!tooltipList.isEmpty()) {
0300             tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + tooltipList.join(QLatin1Char('\n'));
0301         }
0302         if (mResult.listSignatureAuthenticationResult.isEmpty()) {
0303             tooltip += (tooltip.isEmpty() ? QChar() : QLatin1Char('\n')) + i18n("Not Signed");
0304         }
0305     }
0306     qCDebug(MESSAGEVIEWER_DKIMCHECKER_LOG) << "mResult.authentication " << mResult.listSignatureAuthenticationResult;
0307 
0308     mLabel->setToolTip(tooltip);
0309 }
0310 
0311 bool DKIMWidgetInfo::event(QEvent *e)
0312 {
0313     if (e->type() == QEvent::ApplicationPaletteChange) {
0314         updatePalette();
0315     }
0316     return QWidget::event(e);
0317 }
0318 
0319 #include "moc_dkimwidgetinfo.cpp"