1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2009 Andreas Hartmetz <ahartmetz@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "sslui.h"
9
10#include <KLocalizedString>
11#include <KMessageBox>
12#include <ksslcertificatemanager.h>
13#include <ksslerroruidata_p.h>
14#include <ksslinfodialog.h>
15
16bool KIO::SslUi::askIgnoreSslErrors(const KSslErrorUiData &uiData, RulesStorage storedRules)
17{
18 const KSslErrorUiData::Private *ud = KSslErrorUiData::Private::get(uiData: &uiData);
19 if (ud->sslErrors.isEmpty()) {
20 return true;
21 }
22
23 const QList<QSslError> fatalErrors = KSslCertificateManager::nonIgnorableErrors(errors: ud->sslErrors);
24 if (!fatalErrors.isEmpty()) {
25 // TODO message "sorry, fatal error, you can't override it"
26 return false;
27 }
28 if (ud->certificateChain.isEmpty()) {
29 // SSL without certificates is quite useless and should never happen
30 KMessageBox::error(parent: nullptr,
31 i18n("The remote host did not send any SSL certificates.\n"
32 "Aborting because the identity of the host cannot be established."));
33 return false;
34 }
35
36 KSslCertificateManager *const cm = KSslCertificateManager::self();
37 KSslCertificateRule rule(ud->certificateChain.first(), ud->host);
38 if (storedRules & RecallRules) {
39 rule = cm->rule(cert: ud->certificateChain.first(), hostName: ud->host);
40 // remove previously seen and acknowledged errors
41 const QList<QSslError> remainingErrors = rule.filterErrors(errors: ud->sslErrors);
42 if (remainingErrors.isEmpty()) {
43 // qDebug() << "Error list empty after removing errors to be ignored. Continuing.";
44 return true;
45 }
46 }
47
48 // ### We don't ask to permanently reject the certificate
49
50 QString message = i18n("The server failed the authenticity check (%1).\n\n", ud->host);
51 for (const QSslError &err : std::as_const(t: ud->sslErrors)) {
52 message.append(s: err.errorString() + QLatin1Char('\n'));
53 }
54 message = message.trimmed();
55
56 int msgResult;
57 do {
58 msgResult = KMessageBox::warningTwoActionsCancel(parent: nullptr,
59 text: message,
60 i18n("Server Authentication"),
61 primaryAction: KGuiItem(i18n("&Details"), QStringLiteral("help-about")),
62 secondaryAction: KGuiItem(i18n("Co&ntinue"), QStringLiteral("arrow-right")));
63 if (msgResult == KMessageBox::PrimaryAction) {
64 // Details was chosen - show the certificate and error details
65
66 QList<QList<QSslError::SslError>> meh; // parallel list to cert list :/
67
68 meh.reserve(asize: ud->certificateChain.size());
69 for (const QSslCertificate &cert : std::as_const(t: ud->certificateChain)) {
70 QList<QSslError::SslError> errors;
71 for (const QSslError &error : std::as_const(t: ud->sslErrors)) {
72 if (error.certificate() == cert) {
73 // we keep only the error code enum here
74 errors.append(t: error.error());
75 }
76 }
77 meh.append(t: errors);
78 }
79
80 KSslInfoDialog *dialog = new KSslInfoDialog();
81 dialog->setSslInfo(certificateChain: ud->certificateChain, ip: ud->ip, host: ud->host, sslProtocol: ud->sslProtocol, cipher: ud->cipher, usedBits: ud->usedBits, bits: ud->bits, validationErrors: meh);
82 dialog->exec();
83 } else if (msgResult == KMessageBox::Cancel) {
84 return false;
85 }
86 // fall through on KMessageBox::SecondaryAction
87 } while (msgResult == KMessageBox::PrimaryAction);
88
89 if (storedRules & StoreRules) {
90 // Save the user's choice to ignore the SSL errors.
91
92 msgResult = KMessageBox::warningTwoActions(parent: nullptr,
93 i18n("Would you like to accept this "
94 "certificate forever without "
95 "being prompted?"),
96 i18n("Server Authentication"),
97 primaryAction: KGuiItem(i18n("&Forever"), QStringLiteral("flag-green")),
98 secondaryAction: KGuiItem(i18n("&Current Session only"), QStringLiteral("chronometer")));
99 QDateTime ruleExpiry = QDateTime::currentDateTime();
100 if (msgResult == KMessageBox::PrimaryAction) {
101 // accept forever ("for a very long time")
102 ruleExpiry = ruleExpiry.addYears(years: 1000);
103 } else {
104 // accept "for a short time", half an hour.
105 ruleExpiry = ruleExpiry.addSecs(secs: 30 * 60);
106 }
107
108 // TODO special cases for wildcard domain name in the certificate!
109 // rule = KSslCertificateRule(d->socket.peerCertificateChain().first(), whatever);
110
111 rule.setExpiryDateTime(ruleExpiry);
112 rule.setIgnoredErrors(ud->sslErrors);
113 cm->setRule(rule);
114 }
115
116 return true;
117}
118

source code of kio/src/widgets/sslui.cpp