File indexing completed on 2024-12-01 03:41:21
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2009 Andreas Hartmetz <ahartmetz@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "sslui.h" 0009 0010 #include <KLocalizedString> 0011 #include <KMessageBox> 0012 #include <ksslcertificatemanager.h> 0013 #include <ksslerroruidata_p.h> 0014 #include <ksslinfodialog.h> 0015 0016 bool KIO::SslUi::askIgnoreSslErrors(const KSslErrorUiData &uiData, RulesStorage storedRules) 0017 { 0018 const KSslErrorUiData::Private *ud = KSslErrorUiData::Private::get(&uiData); 0019 if (ud->sslErrors.isEmpty()) { 0020 return true; 0021 } 0022 0023 const QList<QSslError> fatalErrors = KSslCertificateManager::nonIgnorableErrors(ud->sslErrors); 0024 if (!fatalErrors.isEmpty()) { 0025 // TODO message "sorry, fatal error, you can't override it" 0026 return false; 0027 } 0028 if (ud->certificateChain.isEmpty()) { 0029 // SSL without certificates is quite useless and should never happen 0030 KMessageBox::error(nullptr, 0031 i18n("The remote host did not send any SSL certificates.\n" 0032 "Aborting because the identity of the host cannot be established.")); 0033 return false; 0034 } 0035 0036 KSslCertificateManager *const cm = KSslCertificateManager::self(); 0037 KSslCertificateRule rule(ud->certificateChain.first(), ud->host); 0038 if (storedRules & RecallRules) { 0039 rule = cm->rule(ud->certificateChain.first(), ud->host); 0040 // remove previously seen and acknowledged errors 0041 const QList<QSslError> remainingErrors = rule.filterErrors(ud->sslErrors); 0042 if (remainingErrors.isEmpty()) { 0043 // qDebug() << "Error list empty after removing errors to be ignored. Continuing."; 0044 return true; 0045 } 0046 } 0047 0048 // ### We don't ask to permanently reject the certificate 0049 0050 QString message = i18n("The server failed the authenticity check (%1).\n\n", ud->host); 0051 for (const QSslError &err : std::as_const(ud->sslErrors)) { 0052 message.append(err.errorString() + QLatin1Char('\n')); 0053 } 0054 message = message.trimmed(); 0055 0056 int msgResult; 0057 do { 0058 msgResult = KMessageBox::warningTwoActionsCancel(nullptr, 0059 message, 0060 i18n("Server Authentication"), 0061 KGuiItem(i18n("&Details"), QStringLiteral("help-about")), 0062 KGuiItem(i18n("Co&ntinue"), QStringLiteral("arrow-right"))); 0063 if (msgResult == KMessageBox::PrimaryAction) { 0064 // Details was chosen - show the certificate and error details 0065 0066 QList<QList<QSslError::SslError>> meh; // parallel list to cert list :/ 0067 0068 meh.reserve(ud->certificateChain.size()); 0069 for (const QSslCertificate &cert : std::as_const(ud->certificateChain)) { 0070 QList<QSslError::SslError> errors; 0071 for (const QSslError &error : std::as_const(ud->sslErrors)) { 0072 if (error.certificate() == cert) { 0073 // we keep only the error code enum here 0074 errors.append(error.error()); 0075 } 0076 } 0077 meh.append(errors); 0078 } 0079 0080 KSslInfoDialog *dialog = new KSslInfoDialog(); 0081 dialog->setSslInfo(ud->certificateChain, ud->ip, ud->host, ud->sslProtocol, ud->cipher, ud->usedBits, ud->bits, meh); 0082 dialog->exec(); 0083 } else if (msgResult == KMessageBox::Cancel) { 0084 return false; 0085 } 0086 // fall through on KMessageBox::SecondaryAction 0087 } while (msgResult == KMessageBox::PrimaryAction); 0088 0089 if (storedRules & StoreRules) { 0090 // Save the user's choice to ignore the SSL errors. 0091 0092 msgResult = KMessageBox::warningTwoActions(nullptr, 0093 i18n("Would you like to accept this " 0094 "certificate forever without " 0095 "being prompted?"), 0096 i18n("Server Authentication"), 0097 KGuiItem(i18n("&Forever"), QStringLiteral("flag-green")), 0098 KGuiItem(i18n("&Current Session only"), QStringLiteral("chronometer"))); 0099 QDateTime ruleExpiry = QDateTime::currentDateTime(); 0100 if (msgResult == KMessageBox::PrimaryAction) { 0101 // accept forever ("for a very long time") 0102 ruleExpiry = ruleExpiry.addYears(1000); 0103 } else { 0104 // accept "for a short time", half an hour. 0105 ruleExpiry = ruleExpiry.addSecs(30 * 60); 0106 } 0107 0108 // TODO special cases for wildcard domain name in the certificate! 0109 // rule = KSslCertificateRule(d->socket.peerCertificateChain().first(), whatever); 0110 0111 rule.setExpiryDateTime(ruleExpiry); 0112 rule.setIgnoredErrors(ud->sslErrors); 0113 cm->setRule(rule); 0114 } 0115 0116 return true; 0117 }