From 8542dc307f6ddf49fd71f4df8d5aa294a6ee03e2 Mon Sep 17 00:00:00 2001 From: nowrep Date: Tue, 3 Jul 2012 15:22:42 +0200 Subject: [PATCH] NetworkManager: Fixed excessive questions about invalid SSL certificate - user will now be asked only once if he rejects the certificate * works only within WebPage, so if user opens new tab, he will get the question again (in case he want to change his mind) --- src/lib/network/networkmanager.cpp | 84 +++++++++++++++++++----------- src/lib/webview/webpage.cpp | 36 +++++++++++-- src/lib/webview/webpage.h | 7 ++- 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/lib/network/networkmanager.cpp b/src/lib/network/networkmanager.cpp index db63fed40..4c35cc172 100644 --- a/src/lib/network/networkmanager.cpp +++ b/src/lib/network/networkmanager.cpp @@ -145,28 +145,18 @@ void NetworkManager::setSSLConfiguration(QNetworkReply* reply) } } +inline uint qHash(const QSslCertificate &cert) +{ + return qHash(cert.toPem()); +} + void NetworkManager::sslError(QNetworkReply* reply, QList errors) { - if (m_ignoreAllWarnings) { + if (m_ignoreAllWarnings || reply->property("downReply").toBool()) { reply->ignoreSslErrors(errors); return; } - if (reply->property("downReply").toBool()) { - return; - } - - int errorsIgnored = 0; - foreach(const QSslError & error, errors) { - if (m_ignoredCerts.contains(error.certificate())) { - ++errorsIgnored; - } - } - - if (errorsIgnored == errors.count()) { - return; - } - QNetworkRequest request = reply->request(); QVariant v = request.attribute((QNetworkRequest::Attribute)(QNetworkRequest::User + 100)); WebPage* webPage = static_cast(v.value()); @@ -174,43 +164,76 @@ void NetworkManager::sslError(QNetworkReply* reply, QList errors) return; } + QHash errorHash; + foreach(const QSslError & error, errors) { + // Weird behavior on Windows + if (error.error() == QSslError::NoError) { + continue; + } + + const QSslCertificate &cert = error.certificate(); + + if (errorHash.contains(cert)) { + errorHash[cert].append(error.errorString()); + } + else { + errorHash.insert(cert, QStringList(error.errorString())); + } + } + + // User already rejected those certs on this page + if (webPage->containsRejectedCerts(errorHash.keys())) { + return; + } + QString title = tr("SSL Certificate Error!"); QString text1 = tr("The page you are trying to access has the following errors in the SSL certificate:"); QString certs; - foreach(const QSslError & error, errors) { - if (m_localCerts.contains(error.certificate())) { - continue; - } - if (error.error() == QSslError::NoError) { //Weird behavior on Windows + QHash::const_iterator i = errorHash.constBegin(); + while (i != errorHash.constEnd()) { + const QSslCertificate &cert = i.key(); + const QStringList &errors = i.value(); + + if (m_localCerts.contains(cert) || errors.isEmpty()) { + ++i; continue; } - QSslCertificate cert = error.certificate(); certs += "
  • "; certs += tr("Organization: ") + CertificateInfoWidget::clearCertSpecialSymbols(cert.subjectInfo(QSslCertificate::Organization)); certs += "
  • "; certs += tr("Domain Name: ") + CertificateInfoWidget::clearCertSpecialSymbols(cert.subjectInfo(QSslCertificate::CommonName)); certs += "
  • "; certs += tr("Expiration Date: ") + cert.expiryDate().toString("hh:mm:ss dddd d. MMMM yyyy"); - certs += "
  • "; - certs += tr("Error: ") + error.errorString(); certs += "
"; + + certs += "
    "; + foreach(const QString & error, errors) { + certs += "
  • "; + certs += tr("Error: ") + error; + certs += "
  • "; + } + certs += "
"; + + ++i; } QString text2 = tr("Would you like to make an exception for this certificate?"); QString message = QString("%1

%2

%3

%4

").arg(title, text1, certs, text2); if (!certs.isEmpty()) { - if (QMessageBox::critical(webPage->view(), tr("SSL Certificate Error!"), message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) { + QMessageBox::StandardButton button = QMessageBox::critical(webPage->view(), tr("SSL Certificate Error!"), message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if (button == QMessageBox::No) { + // To prevent asking user more than once for the same certificate + webPage->addRejectedCerts(errorHash.keys()); return; } - foreach(const QSslError & error, errors) { - if (!m_localCerts.contains(error.certificate())) { - addLocalCertificate(error.certificate()); + foreach(const QSslCertificate & cert, errorHash.keys()) { + if (!m_localCerts.contains(cert)) { + addLocalCertificate(cert); } } } @@ -365,11 +388,12 @@ QNetworkReply* NetworkManager::createRequest(QNetworkAccessManager::Operation op void NetworkManager::removeLocalCertificate(const QSslCertificate &cert) { m_localCerts.removeOne(cert); + QList certs = QSslSocket::defaultCaCertificates(); certs.removeOne(cert); QSslSocket::setDefaultCaCertificates(certs); - //Delete cert file from profile + // Delete cert file from profile bool deleted = false; QDirIterator it(mApp->currentProfilePath() + "certificates", QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories); while (it.hasNext()) { diff --git a/src/lib/webview/webpage.cpp b/src/lib/webview/webpage.cpp index 28bfcd5bc..16d3fc23b 100644 --- a/src/lib/webview/webpage.cpp +++ b/src/lib/webview/webpage.cpp @@ -67,6 +67,7 @@ WebPage::WebPage(QupZilla* mainClass) , m_speedDial(mApp->plugins()->speedDial()) , m_fileWatcher(0) , m_runningLoop(0) + , m_loadProgress(-1) , m_blockAlerts(false) , m_secureStatus(false) , m_adjustingScheduled(false) @@ -142,11 +143,38 @@ bool WebPage::loadingError() const return !mainFrame()->findFirstElement("span[id=\"qupzilla-error-page\"]").isNull(); } +void WebPage::addRejectedCerts(const QList &certs) +{ + foreach(const QSslCertificate & cert, certs) { + if (!m_rejectedSslCerts.contains(cert)) { + m_rejectedSslCerts.append(cert); + } + } +} + +bool WebPage::containsRejectedCerts(const QList &certs) const +{ + int matches = 0; + + foreach(const QSslCertificate & cert, certs) { + if (m_rejectedSslCerts.contains(cert)) { + ++matches; + } + } + + return matches == certs.count(); +} + bool WebPage::isRunningLoop() { return m_runningLoop; } +bool WebPage::isLoading() const +{ + return m_loadProgress < 100; +} + void WebPage::setUserAgent(const QString &agent) { if (!agent.isEmpty()) { @@ -161,13 +189,15 @@ void WebPage::urlChanged(const QUrl &url) { Q_UNUSED(url) - m_adBlockedEntries.clear(); - m_blockAlerts = false; + if (isLoading()) { + m_adBlockedEntries.clear(); + m_blockAlerts = false; + } } void WebPage::progress(int prog) { - Q_UNUSED(prog) + m_loadProgress = prog; bool secStatus = sslCertificate().isValid(); diff --git a/src/lib/webview/webpage.h b/src/lib/webview/webpage.h index b30331bb9..8434b4b7f 100644 --- a/src/lib/webview/webpage.h +++ b/src/lib/webview/webpage.h @@ -67,8 +67,12 @@ public: void scheduleAdjustPage(); bool isRunningLoop(); + bool isLoading() const; bool loadingError() const; + void addRejectedCerts(const QList &certs); + bool containsRejectedCerts(const QList &certs) const; + static void setUserAgent(const QString &agent); QString userAgentForUrl(const QUrl &url) const; @@ -123,12 +127,13 @@ private: TabbedWebView* m_view; SpeedDial* m_speedDial; QSslCertificate m_SslCert; - QList m_SslCerts; + QList m_rejectedSslCerts; QList m_adBlockedEntries; QFileSystemWatcher* m_fileWatcher; QEventLoop* m_runningLoop; + int m_loadProgress; bool m_blockAlerts; bool m_secureStatus; bool m_adjustingScheduled;