Build a cache of allowed SSL exceptions and use them on future network requests

The   class  NetworkAccessManager   sub-classes  QNetworkAccessManager
adding  a  message  box  to  ask   the  user  if  SSL  errors  may  be
ignored. Ignored errors  are ignored in future server  replies so that
the user is not asked about he same peer certificate chain repeatedly.
The cache is currently per process only and not persistent.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7361 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2016-12-04 14:17:01 +00:00
parent a4b7df3099
commit 4975c04234
4 changed files with 73 additions and 27 deletions

63
NetworkAccessManager.hpp Normal file
View File

@ -0,0 +1,63 @@
#ifndef NETWORK_ACCESS_MANAGER_HPP__
#define NETWORK_ACCESS_MANAGER_HPP__
#include <QNetworkAccessManager>
#include <QList>
#include <QSslError>
#include <QNetworkReply>
#include <QString>
#include "MessageBox.hpp"
class QNetworkRequest;
class QIODevice;
class QWidget;
// sub-class QNAM to keep a list of accepted SSL errors and allow
// them in future replies
class NetworkAccessManager
: public QNetworkAccessManager
{
public:
NetworkAccessManager (QWidget * parent = nullptr)
: QNetworkAccessManager (parent)
{
// handle SSL errors that have not been cached as allowed
// exceptions and offer them to the user to add to the ignored
// exception cache
connect (this, &QNetworkAccessManager::sslErrors, [this, &parent] (QNetworkReply * reply, QList<QSslError> const& errors) {
QString message;
for (auto const& error: errors)
{
message += '\n' + reply->request ().url ().toDisplayString () + ": "
+ error.errorString ();
}
QString certs;
for (auto const& cert : reply->sslConfiguration ().peerCertificateChain ())
{
certs += cert.toText () + '\n';
}
if (MessageBox::Ignore == MessageBox::query_message (parent, tr ("Network SSL Errors"), message, certs, MessageBox::Abort | MessageBox::Ignore))
{
// accumulate SSL error exceptions that have been allowed
allowed_ssl_errors_.append (errors);
reply->ignoreSslErrors (errors);
}
});
}
protected:
QNetworkReply * createRequest (Operation operation, QNetworkRequest const& request, QIODevice * outgoing_data = nullptr) override
{
auto reply = QNetworkAccessManager::createRequest (operation, request, outgoing_data);
// errors are usually certificate specific so passing all cached
// exceptions here is ok
reply->ignoreSslErrors (allowed_ssl_errors_);
return reply;
}
private:
QList<QSslError> allowed_ssl_errors_;
};
#endif

View File

@ -8,8 +8,6 @@
#include <QDateTime>
#include <QApplication>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QRegularExpression>
#include <QObject>
#include <QSettings>
@ -316,25 +314,8 @@ int main(int argc, char *argv[])
).toBool () ? 1u : 4u;
}
QNetworkAccessManager network_manager {&a};
// run the application UI
MainWindow w(temp_dir, multiple, &multi_settings, &mem_jt9, downSampleFactor, &network_manager, &splash);
// set up handling for any SSL issues
QObject::connect (&network_manager, &QNetworkAccessManager::sslErrors, [&w] (QNetworkReply * reply, QList<QSslError> const& errors) {
QString message;
for (auto const& error: errors)
{
message += '\n' + reply->request ().url ().toDisplayString () + ": "
+ error.errorString ();
}
if (QMessageBox::Ignore == QMessageBox::question (&w, "Network SSL Errors", message, QMessageBox::Abort | QMessageBox::Ignore))
{
reply->ignoreSslErrors ();
}
});
MainWindow w(temp_dir, multiple, &multi_settings, &mem_jt9, downSampleFactor, &splash);
w.show();
splash.raise ();
QObject::connect (&a, SIGNAL (lastWindowClosed()), &a, SLOT (quit()));

View File

@ -26,6 +26,7 @@
#include "revision_utils.hpp"
#include "qt_helpers.hpp"
#include "NetworkAccessManager.hpp"
#include "soundout.h"
#include "soundin.h"
#include "Modulator.hpp"
@ -157,9 +158,10 @@ namespace
//--------------------------------------------------- MainWindow constructor
MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
MultiSettings * multi_settings, QSharedMemory *shdmem,
unsigned downSampleFactor, QNetworkAccessManager * network_manager,
unsigned downSampleFactor,
QSplashScreen * splash, QWidget *parent) :
QMainWindow(parent),
m_network_manager {this},
m_valid {true},
m_splash {splash},
m_dataDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)},
@ -254,7 +256,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_onAirFreq0 {0.0},
m_first_error {true},
tx_status_label {"Receiving"},
wsprNet {new WSPRNet {network_manager, this}},
wsprNet {new WSPRNet {&m_network_manager, this}},
m_appDir {QApplication::applicationDirPath ()},
m_palette {"Linrad"},
m_mode {"JT9"},
@ -336,7 +338,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_config.udp_server_name (), m_config.udp_server_port (),
this}},
psk_Reporter {new PSK_Reporter {m_messageClient, this}},
m_manual {network_manager}
m_manual {&m_network_manager}
{
ui->setupUi(this);
createStatusBar();
@ -485,10 +487,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->actionMediumDecode->setActionGroup(DepthGroup);
ui->actionDeepestDecode->setActionGroup(DepthGroup);
connect (ui->download_samples_action, &QAction::triggered, [this, network_manager] () {
connect (ui->download_samples_action, &QAction::triggered, [this] () {
if (!m_sampleDownloader)
{
m_sampleDownloader.reset (new SampleDownloader {m_settings, &m_config, network_manager, this});
m_sampleDownloader.reset (new SampleDownloader {m_settings, &m_config, &m_network_manager, this});
}
m_sampleDownloader->show ();
});

View File

@ -35,6 +35,7 @@
#include "commons.h"
#include "astro.h"
#include "MessageBox.hpp"
#include "NetworkAccessManager.hpp"
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
@ -55,7 +56,6 @@ namespace Ui {
}
class QSettings;
class QNetworkAccessManager;
class QLineEdit;
class QFont;
class QHostInfo;
@ -88,7 +88,6 @@ public:
explicit MainWindow(QDir const& temp_directory, bool multiple, MultiSettings *,
QSharedMemory *shdmem, unsigned downSampleFactor,
QNetworkAccessManager * network_manager,
QSplashScreen *,
QWidget *parent = nullptr);
~MainWindow();
@ -279,6 +278,7 @@ private:
void astroUpdate ();
void writeAllTxt(QString message);
NetworkAccessManager m_network_manager;
bool m_valid;
QSplashScreen * m_splash;
QDir m_dataDir;