mirror of
https://github.com/qbittorrent/qBittorrent
synced 2025-07-12 16:23:07 -07:00
Load WebUI certificate & key from file path
This allow users to update certificate & key more easily, i.e. without the need to import them into qbt. Closes #6675, #7547, #8315, #8564.
This commit is contained in:
parent
48d358872f
commit
5cdb3b6a2d
12 changed files with 212 additions and 277 deletions
|
@ -30,55 +30,69 @@
|
|||
|
||||
#include "server.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QMutableListIterator>
|
||||
#include <QNetworkProxy>
|
||||
#include <QSslCipher>
|
||||
#include <QSslSocket>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
#ifndef QT_NO_OPENSSL
|
||||
#include <QSslSocket>
|
||||
#else
|
||||
#include <QTcpSocket>
|
||||
#endif
|
||||
|
||||
#include "base/utils/net.h"
|
||||
#include "connection.h"
|
||||
|
||||
static const int KEEP_ALIVE_DURATION = 7 * 1000; // milliseconds
|
||||
static const int CONNECTIONS_LIMIT = 500;
|
||||
static const int CONNECTIONS_SCAN_INTERVAL = 2; // seconds
|
||||
namespace
|
||||
{
|
||||
const int KEEP_ALIVE_DURATION = 7 * 1000; // milliseconds
|
||||
const int CONNECTIONS_LIMIT = 500;
|
||||
const int CONNECTIONS_SCAN_INTERVAL = 2; // seconds
|
||||
|
||||
QList<QSslCipher> safeCipherList()
|
||||
{
|
||||
const QStringList badCiphers = {"idea", "rc4"};
|
||||
const QList<QSslCipher> allCiphers = QSslSocket::supportedCiphers();
|
||||
QList<QSslCipher> safeCiphers;
|
||||
for (const QSslCipher &cipher : allCiphers) {
|
||||
bool isSafe = true;
|
||||
for (const QString &badCipher : badCiphers) {
|
||||
if (cipher.name().contains(badCipher, Qt::CaseInsensitive)) {
|
||||
isSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSafe)
|
||||
safeCiphers += cipher;
|
||||
}
|
||||
|
||||
return safeCiphers;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Http;
|
||||
|
||||
Server::Server(IRequestHandler *requestHandler, QObject *parent)
|
||||
: QTcpServer(parent)
|
||||
, m_requestHandler(requestHandler)
|
||||
#ifndef QT_NO_OPENSSL
|
||||
, m_https(false)
|
||||
#endif
|
||||
{
|
||||
setProxy(QNetworkProxy::NoProxy);
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QSslSocket::setDefaultCiphers(safeCipherList());
|
||||
#endif
|
||||
|
||||
QTimer *dropConnectionTimer = new QTimer(this);
|
||||
connect(dropConnectionTimer, &QTimer::timeout, this, &Server::dropTimedOutConnection);
|
||||
dropConnectionTimer->start(CONNECTIONS_SCAN_INTERVAL * 1000);
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
{
|
||||
}
|
||||
|
||||
void Server::incomingConnection(qintptr socketDescriptor)
|
||||
{
|
||||
if (m_connections.size() >= CONNECTIONS_LIMIT) return;
|
||||
|
||||
QTcpSocket *serverSocket;
|
||||
#ifndef QT_NO_OPENSSL
|
||||
if (m_https)
|
||||
serverSocket = new QSslSocket(this);
|
||||
else
|
||||
#endif
|
||||
serverSocket = new QTcpSocket(this);
|
||||
|
||||
if (!serverSocket->setSocketDescriptor(socketDescriptor)) {
|
||||
|
@ -86,7 +100,6 @@ void Server::incomingConnection(qintptr socketDescriptor)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
if (m_https) {
|
||||
static_cast<QSslSocket *>(serverSocket)->setProtocol(QSsl::SecureProtocols);
|
||||
static_cast<QSslSocket *>(serverSocket)->setPrivateKey(m_key);
|
||||
|
@ -94,7 +107,6 @@ void Server::incomingConnection(qintptr socketDescriptor)
|
|||
static_cast<QSslSocket *>(serverSocket)->setPeerVerifyMode(QSslSocket::VerifyNone);
|
||||
static_cast<QSslSocket *>(serverSocket)->startServerEncryption();
|
||||
}
|
||||
#endif
|
||||
|
||||
Connection *c = new Connection(serverSocket, m_requestHandler, this);
|
||||
m_connections.append(c);
|
||||
|
@ -112,26 +124,20 @@ void Server::dropTimedOutConnection()
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef QT_NO_OPENSSL
|
||||
bool Server::setupHttps(const QByteArray &certificates, const QByteArray &key)
|
||||
bool Server::setupHttps(const QByteArray &certificates, const QByteArray &privateKey)
|
||||
{
|
||||
QSslKey sslKey(key, QSsl::Rsa);
|
||||
if (sslKey.isNull())
|
||||
sslKey = QSslKey(key, QSsl::Ec);
|
||||
const QList<QSslCertificate> certs {Utils::Net::loadSSLCertificate(certificates)};
|
||||
const QSslKey key {Utils::Net::loadSSLKey(privateKey)};
|
||||
|
||||
const QList<QSslCertificate> certs = QSslCertificate::fromData(certificates);
|
||||
const bool areCertsValid = !certs.empty() && std::all_of(certs.begin(), certs.end(), [](const QSslCertificate &c) { return !c.isNull(); });
|
||||
|
||||
if (!sslKey.isNull() && areCertsValid) {
|
||||
m_key = sslKey;
|
||||
m_certificates = certs;
|
||||
m_https = true;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (certs.isEmpty() || key.isNull()) {
|
||||
disableHttps();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_key = key;
|
||||
m_certificates = certs;
|
||||
m_https = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Server::disableHttps()
|
||||
|
@ -140,25 +146,3 @@ void Server::disableHttps()
|
|||
m_certificates.clear();
|
||||
m_key.clear();
|
||||
}
|
||||
|
||||
QList<QSslCipher> Server::safeCipherList() const
|
||||
{
|
||||
const QStringList badCiphers = {"idea", "rc4"};
|
||||
const QList<QSslCipher> allCiphers = QSslSocket::supportedCiphers();
|
||||
QList<QSslCipher> safeCiphers;
|
||||
for (const QSslCipher &cipher : allCiphers) {
|
||||
bool isSafe = true;
|
||||
for (const QString &badCipher : badCiphers) {
|
||||
if (cipher.name().contains(badCipher, Qt::CaseInsensitive)) {
|
||||
isSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSafe)
|
||||
safeCiphers += cipher;
|
||||
}
|
||||
|
||||
return safeCiphers;
|
||||
}
|
||||
#endif // QT_NO_OPENSSL
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue