mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-20 02:50:46 -06:00
dbhub: Add basic HTTPS support
This adds basic support for fetching databases via HTTPS using client certificates. You can include CA certificates to verify any responses from a server. For now, one test CA certificate is included but it's easy to add more. It's also possible to authentify the client using a client certificate, a client key and a password. As of this commit all three items are hardcoded. It's still possible to access any remote database via HTTP but if a request URL starts with 'https' this new mechanism will be used. All certificates, keys, and password included in here are taken from my node.js test server repository. They will be replaced soon-ish.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkReply>
|
||||
#include <QFile>
|
||||
#include <QSslKey>
|
||||
|
||||
#include "RemoteDatabase.h"
|
||||
#include "version.h"
|
||||
@@ -12,7 +13,8 @@ RemoteDatabase::RemoteDatabase() :
|
||||
m_manager(new QNetworkAccessManager),
|
||||
m_currentReply(nullptr)
|
||||
{
|
||||
// TODO Set up SSL configuration here
|
||||
// Load settings and set up some more stuff while doing so
|
||||
reloadSettings();
|
||||
|
||||
// TODO Add support for proxies here
|
||||
|
||||
@@ -27,6 +29,40 @@ RemoteDatabase::~RemoteDatabase()
|
||||
delete m_manager;
|
||||
}
|
||||
|
||||
void RemoteDatabase::reloadSettings()
|
||||
{
|
||||
// Set up SSL configuration
|
||||
m_sslConfiguration = QSslConfiguration::defaultConfiguration();
|
||||
m_sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyPeer);
|
||||
|
||||
// Load CA certs from resource file
|
||||
QDir dirCaCerts(":/certs");
|
||||
QStringList caCertsList = dirCaCerts.entryList();
|
||||
QList<QSslCertificate> caCerts;
|
||||
foreach(const QString& caCertName, caCertsList)
|
||||
{
|
||||
QFile fileCaCert(":/certs/" + caCertName);
|
||||
fileCaCert.open(QFile::ReadOnly);
|
||||
caCerts.push_back(QSslCertificate(&fileCaCert));
|
||||
fileCaCert.close();
|
||||
}
|
||||
m_sslConfiguration.setCaCertificates(caCerts);
|
||||
|
||||
// Load client cert
|
||||
QFile fileClientCert("client.crt");
|
||||
fileClientCert.open(QFile::ReadOnly);
|
||||
QSslCertificate clientCert(&fileClientCert);
|
||||
fileClientCert.close();
|
||||
m_sslConfiguration.setLocalCertificate(clientCert);
|
||||
|
||||
// Load private key
|
||||
QFile fileClientKey("client.key");
|
||||
fileClientKey.open(QFile::ReadOnly);
|
||||
QSslKey clientKey(&fileClientKey, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "password");
|
||||
fileClientKey.close();
|
||||
m_sslConfiguration.setPrivateKey(clientKey);
|
||||
}
|
||||
|
||||
void RemoteDatabase::fetchDatabase(const QString& url)
|
||||
{
|
||||
// Check if network is accessible. If not, abort right here
|
||||
@@ -41,7 +77,10 @@ void RemoteDatabase::fetchDatabase(const QString& url)
|
||||
request.setUrl(url);
|
||||
request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName()).arg(APP_VERSION).toUtf8());
|
||||
|
||||
// TODO Set SSL configuration here
|
||||
// Set SSL configuration when trying to access a file via the HTTPS protocol
|
||||
bool https = QUrl(url).scheme().compare("https", Qt::CaseInsensitive) == 0;
|
||||
if(https)
|
||||
request.setSslConfiguration(m_sslConfiguration);
|
||||
|
||||
// Fetch database and save pending reply. Note that we're only supporting one active download here at the moment.
|
||||
m_currentReply = m_manager->get(request);
|
||||
@@ -55,9 +94,12 @@ void RemoteDatabase::fetchDatabase(const QString& url)
|
||||
connect(m_currentReply, &QNetworkReply::downloadProgress, this, &RemoteDatabase::updateProgress);
|
||||
}
|
||||
|
||||
void RemoteDatabase::gotEncrypted(QNetworkReply* /*reply*/)
|
||||
void RemoteDatabase::gotEncrypted(QNetworkReply* reply)
|
||||
{
|
||||
// TODO Check SSL configuration here and abort reply if it's not good
|
||||
// Verify the server's certificate using our CA certs. If it's not good, abort the reply here
|
||||
auto verificationErrors = reply->sslConfiguration().peerCertificate().verify(m_sslConfiguration.caCertificates());
|
||||
if(!(verificationErrors.size() == 0 || (verificationErrors.size() == 1 && verificationErrors.at(0).error() == QSslError::SelfSignedCertificate)))
|
||||
reply->abort();
|
||||
}
|
||||
|
||||
void RemoteDatabase::gotReply(QNetworkReply* reply)
|
||||
@@ -93,6 +135,25 @@ void RemoteDatabase::gotReply(QNetworkReply* reply)
|
||||
|
||||
void RemoteDatabase::gotError(QNetworkReply* reply, const QList<QSslError>& errors)
|
||||
{
|
||||
// Are there any errors in here that aren't about self-signed certificates and non-matching hostnames?
|
||||
// TODO What about the hostname mismatch? Can we remove that from the list of ignored errors later?
|
||||
bool serious_errors = false;
|
||||
foreach(const QSslError& error, errors)
|
||||
{
|
||||
if(error.error() != QSslError::SelfSignedCertificate && error.error() != QSslError::HostNameMismatch)
|
||||
{
|
||||
serious_errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Just stop the error checking here and accept the reply if there were no 'serious' errors
|
||||
if(!serious_errors)
|
||||
{
|
||||
reply->ignoreSslErrors(errors);
|
||||
return;
|
||||
}
|
||||
|
||||
// Build an error message and short it to the user
|
||||
QString message = tr("Error opening remote database file from %1.\n%2").arg(reply->url().toString()).arg(errors.at(0).errorString());
|
||||
QMessageBox::warning(0, qApp->applicationName(), message);
|
||||
|
||||
Reference in New Issue
Block a user