File indexing completed on 2024-12-22 05:05:21
0001 // SPDX-FileCopyrightText: 2023 g10 Code GmbH 0002 // SPDX-FileContributor: Carl Schwan <carl.schwan@gnupg.com> 0003 // SPDX-License-Identifier: LGPL-2.0-or-later 0004 0005 #include "../core/utils.h" 0006 #include "messagecontainerwidget_p.h" 0007 #include "urlhandler_p.h" 0008 0009 #include <KLocalizedString> 0010 #include <KMessageWidget> 0011 #include <Libkleo/Compliance> 0012 #include <Libkleo/Formatting> 0013 #include <QGpgME/Protocol> 0014 0015 #include <QLabel> 0016 #include <QPaintEvent> 0017 #include <QPainter> 0018 #include <QVBoxLayout> 0019 0020 namespace 0021 { 0022 0023 const int borderWidth = 5; 0024 0025 QColor getColor(PartModel::SecurityLevel securityLevel) 0026 { 0027 const static QHash<PartModel::SecurityLevel, QColor> colors{ 0028 {PartModel::Good, QColor(39, 174, 96)}, // Window: ForegroundPositive 0029 {PartModel::Bad, QColor(218, 68, 83)}, // Window: ForegroundNegative 0030 {PartModel::NotSoGood, QColor(246, 116, 0)}, // Window: ForegroundNeutral 0031 }; 0032 0033 return colors.value(securityLevel, QColor()); 0034 } 0035 0036 KMessageWidget::MessageType getType(PartModel::SecurityLevel securityLevel) 0037 { 0038 const static QHash<PartModel::SecurityLevel, KMessageWidget::MessageType> messageTypes{ 0039 {PartModel::Good, KMessageWidget::MessageType::Positive}, 0040 {PartModel::Bad, KMessageWidget::MessageType::Error}, 0041 {PartModel::NotSoGood, KMessageWidget::MessageType::Warning}, 0042 }; 0043 0044 return messageTypes.value(securityLevel, KMessageWidget::MessageType::Information); 0045 } 0046 0047 QString getDetails(const SignatureInfo &signatureDetails) 0048 { 0049 QString href; 0050 if (signatureDetails.cryptoProto) { 0051 href = QStringLiteral("messageviewer:showCertificate#%1 ### %2 ### %3") 0052 .arg(signatureDetails.cryptoProto->displayName(), signatureDetails.cryptoProto->name(), QString::fromLatin1(signatureDetails.keyId)); 0053 } 0054 0055 QString details; 0056 if (signatureDetails.keyMissing) { 0057 if (Kleo::DeVSCompliance::isCompliant() && signatureDetails.isCompliant) { 0058 details += i18ndc("mimetreeparser", 0059 "@label", 0060 "This message has been signed VS-NfD compliant using the certificate <a href=\"%1\">%2</a>.", 0061 href, 0062 Kleo::Formatting::prettyID(signatureDetails.keyId.toStdString().data())) 0063 + QLatin1Char('\n'); 0064 } else { 0065 details += i18ndc("mimetreeparser", 0066 "@label", 0067 "This message has been signed using the certificate <a href=\"%1\">%2</a>.", 0068 href, 0069 Kleo::Formatting::prettyID(signatureDetails.keyId.toStdString().data())) 0070 + QLatin1Char('\n'); 0071 } 0072 details += i18ndc("mimetreeparser", "@label", "The certificate details are not available."); 0073 } else { 0074 QString signerDisplayName = signatureDetails.signer.toHtmlEscaped(); 0075 if (signatureDetails.cryptoProto == QGpgME::smime()) { 0076 Kleo::DN dn(signatureDetails.signer); 0077 signerDisplayName = MimeTreeParser::dnToDisplayName(dn).toHtmlEscaped(); 0078 } 0079 if (Kleo::DeVSCompliance::isCompliant() && signatureDetails.isCompliant) { 0080 details += i18ndc("mimetreeparser", "@label", "This message has been signed VS-NfD compliant by %1.", signerDisplayName); 0081 } else { 0082 details += i18ndc("mimetreeparser", "@label", "This message has been signed by %1.", signerDisplayName); 0083 } 0084 if (signatureDetails.keyRevoked) { 0085 details += QLatin1Char('\n') + i18ndc("mimetreeparser", "@label", "The <a href=\"%1\">certificate</a> was revoked.", href); 0086 } 0087 if (signatureDetails.keyExpired) { 0088 details += QLatin1Char('\n') + i18ndc("mimetreeparser", "@label", "The <a href=\"%1\">certificate</a> was expired.", href); 0089 } 0090 0091 if (signatureDetails.keyTrust == GpgME::Signature::Unknown) { 0092 details += QLatin1Char(' ') 0093 + i18ndc("mimetreeparser", "@label", "The signature is valid, but the <a href=\"%1\">certificate</a>'s validity is unknown.", href); 0094 } else if (signatureDetails.keyTrust == GpgME::Signature::Marginal) { 0095 details += QLatin1Char(' ') 0096 + i18ndc("mimetreeparser", "@label", "The signature is valid and the <a href=\"%1\">certificate</a> is marginally trusted.", href); 0097 } else if (signatureDetails.keyTrust == GpgME::Signature::Full) { 0098 details += 0099 QLatin1Char(' ') + i18ndc("mimetreeparser", "@label", "The signature is valid and the <a href=\"%1\">certificate</a> is fully trusted.", href); 0100 } else if (signatureDetails.keyTrust == GpgME::Signature::Ultimate) { 0101 details += QLatin1Char(' ') 0102 + i18ndc("mimetreeparser", "@label", "The signature is valid and the <a href=\"%1\">certificate</a> is ultimately trusted.", href); 0103 } else { 0104 details += 0105 QLatin1Char(' ') + i18ndc("mimetreeparser", "@label", "The signature is valid, but the <a href=\"%1\">certificate</a> is untrusted.", href); 0106 } 0107 if (!signatureDetails.signatureIsGood && !signatureDetails.keyRevoked && !signatureDetails.keyExpired 0108 && signatureDetails.keyTrust != GpgME::Signature::Unknown) { 0109 details += QLatin1Char(' ') + i18ndc("mimetreeparser", "@label", "The signature is invalid."); 0110 } 0111 } 0112 return details; 0113 } 0114 0115 } 0116 0117 MessageWidgetContainer::MessageWidgetContainer(bool isSigned, 0118 const SignatureInfo &signatureInfo, 0119 PartModel::SecurityLevel signatureSecurityLevel, 0120 bool displaySignatureInfo, 0121 bool isEncrypted, 0122 const SignatureInfo &encryptionInfo, 0123 PartModel::SecurityLevel encryptionSecurityLevel, 0124 bool displayEncryptionInfo, 0125 UrlHandler *urlHandler, 0126 QWidget *parent) 0127 : QFrame(parent) 0128 , m_isSigned(isSigned) 0129 , m_signatureInfo(signatureInfo) 0130 , m_signatureSecurityLevel(signatureSecurityLevel) 0131 , m_displaySignatureInfo(displaySignatureInfo) 0132 , m_isEncrypted(isEncrypted) 0133 , m_encryptionInfo(encryptionInfo) 0134 , m_encryptionSecurityLevel(encryptionSecurityLevel) 0135 , m_displayEncryptionInfo(displayEncryptionInfo) 0136 , m_urlHandler(urlHandler) 0137 { 0138 createLayout(); 0139 } 0140 0141 MessageWidgetContainer::~MessageWidgetContainer() = default; 0142 0143 void MessageWidgetContainer::paintEvent(QPaintEvent *event) 0144 { 0145 Q_UNUSED(event) 0146 0147 if (!m_isSigned && !m_isEncrypted) { 0148 return; 0149 } 0150 0151 QPainter painter(this); 0152 if (layoutDirection() == Qt::RightToLeft) { 0153 auto r = rect(); 0154 r.setX(width() - borderWidth); 0155 r.setWidth(borderWidth); 0156 const QColor color = getColor(PartModel::SecurityLevel::Good); 0157 painter.setRenderHint(QPainter::Antialiasing); 0158 painter.setBrush(QColor(color)); 0159 painter.setPen(QPen(Qt::NoPen)); 0160 painter.drawRect(r); 0161 } else { 0162 auto r = rect(); 0163 r.setWidth(borderWidth); 0164 const QColor color = getColor(PartModel::SecurityLevel::Good); 0165 painter.setRenderHint(QPainter::Antialiasing); 0166 painter.setBrush(QColor(color)); 0167 painter.setPen(QPen(Qt::NoPen)); 0168 painter.drawRect(r); 0169 } 0170 } 0171 0172 bool MessageWidgetContainer::event(QEvent *event) 0173 { 0174 if (event->type() == QEvent::Polish && !layout()) { 0175 createLayout(); 0176 } 0177 0178 return QFrame::event(event); 0179 } 0180 0181 void MessageWidgetContainer::createLayout() 0182 { 0183 delete layout(); 0184 0185 auto vLayout = new QVBoxLayout(this); 0186 0187 if (m_isSigned || m_isEncrypted) { 0188 if (layoutDirection() == Qt::RightToLeft) { 0189 layout()->setContentsMargins(0, 0, borderWidth * 2, 0); 0190 } else { 0191 layout()->setContentsMargins(borderWidth * 2, 0, 0, 0); 0192 } 0193 } 0194 0195 if (m_isEncrypted && m_displayEncryptionInfo) { 0196 auto encryptionMessage = new KMessageWidget(this); 0197 encryptionMessage->setObjectName(QLatin1StringView("EncryptionMessage")); 0198 encryptionMessage->setCloseButtonVisible(false); 0199 0200 QString text; 0201 if (m_encryptionInfo.keyId.isEmpty()) { 0202 encryptionMessage->setIcon(QIcon::fromTheme(QStringLiteral("data-error"))); 0203 encryptionMessage->setMessageType(KMessageWidget::Error); 0204 if (Kleo::DeVSCompliance::isCompliant() && m_encryptionInfo.isCompliant) { 0205 text = i18n("This message is VS-NfD compliant encrypted but we don't have the certificate for it.", QString::fromUtf8(m_encryptionInfo.keyId)); 0206 } else { 0207 text = i18n("This message is encrypted but we don't have the certificate for it."); 0208 } 0209 } else { 0210 encryptionMessage->setIcon(QIcon::fromTheme(QStringLiteral("mail-encrypted"))); 0211 encryptionMessage->setMessageType(KMessageWidget::Positive); 0212 if (Kleo::DeVSCompliance::isCompliant() && m_encryptionInfo.isCompliant) { 0213 text = i18n("This message is VS-NfD compliant encrypted."); 0214 } else { 0215 text = i18n("This message is encrypted."); 0216 } 0217 } 0218 0219 encryptionMessage->setText(text + QLatin1Char(' ') + QStringLiteral("<a href=\"messageviewer:showDetails\">Details</a>")); 0220 0221 connect(encryptionMessage, &KMessageWidget::linkActivated, this, [this, encryptionMessage, text](const QString &link) { 0222 QUrl url(link); 0223 if (url.path() == QStringLiteral("showDetails")) { 0224 QString newText = text + QLatin1Char(' ') + i18n("The message is encrypted for the following certificates:"); 0225 0226 newText += MimeTreeParser::decryptRecipientsToHtml(m_encryptionInfo.decryptRecipients, m_encryptionInfo.cryptoProto); 0227 0228 encryptionMessage->setText(newText); 0229 return; 0230 } 0231 0232 if (url.path() == QStringLiteral("showCertificate")) { 0233 m_urlHandler->handleClick(QUrl(link), window()->windowHandle()); 0234 } 0235 }); 0236 0237 vLayout->addWidget(encryptionMessage); 0238 } 0239 0240 if (m_isSigned && m_displaySignatureInfo) { 0241 auto signatureMessage = new KMessageWidget(this); 0242 signatureMessage->setObjectName(QStringLiteral("SignatureMessage")); 0243 signatureMessage->setCloseButtonVisible(false); 0244 signatureMessage->setText(getDetails(m_signatureInfo)); 0245 connect(signatureMessage, &KMessageWidget::linkActivated, this, [this](const QString &link) { 0246 m_urlHandler->handleClick(QUrl(link), window()->windowHandle()); 0247 }); 0248 signatureMessage->setMessageType(getType(m_signatureSecurityLevel)); 0249 switch (m_signatureSecurityLevel) { 0250 case PartModel::Good: 0251 signatureMessage->setIcon(QIcon::fromTheme(QStringLiteral("mail-signed"))); 0252 break; 0253 case PartModel::Bad: 0254 signatureMessage->setIcon(QIcon::fromTheme(QStringLiteral("data-error"))); 0255 break; 0256 case PartModel::NotSoGood: 0257 signatureMessage->setIcon(QIcon::fromTheme(QStringLiteral("data-warning"))); 0258 break; 0259 default: 0260 break; 0261 } 0262 signatureMessage->setWordWrap(true); 0263 0264 vLayout->addWidget(signatureMessage); 0265 } 0266 } 0267 0268 #include "moc_messagecontainerwidget_p.cpp"