qt: cleanup: Move BIP70 functions together in paymentserver
Reduces the number of separate `#ifdefs` spans.
This commit is contained in:
parent
9dcf6c0dfe
commit
38b98507cd
2 changed files with 149 additions and 160 deletions
|
@ -57,21 +57,6 @@ const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
|
|||
const char* BIP71_MIMETYPE_PAYMENT = "application/bitcoin-payment";
|
||||
const char* BIP71_MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
|
||||
const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
|
||||
|
||||
struct X509StoreDeleter {
|
||||
void operator()(X509_STORE* b) {
|
||||
X509_STORE_free(b);
|
||||
}
|
||||
};
|
||||
|
||||
struct X509Deleter {
|
||||
void operator()(X509* b) { X509_free(b); }
|
||||
};
|
||||
|
||||
namespace // Anon namespace
|
||||
{
|
||||
std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
|
@ -99,96 +84,6 @@ static QString ipcServerName()
|
|||
|
||||
static QList<QString> savedPaymentRequests;
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
static void ReportInvalidCertificate(const QSslCertificate& cert)
|
||||
{
|
||||
qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
|
||||
}
|
||||
|
||||
//
|
||||
// Load OpenSSL's list of root certificate authorities
|
||||
//
|
||||
void PaymentServer::LoadRootCAs(X509_STORE* _store)
|
||||
{
|
||||
// Unit tests mostly use this, to pass in fake root CAs:
|
||||
if (_store)
|
||||
{
|
||||
certStore.reset(_store);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal execution, use either -rootcertificates or system certs:
|
||||
certStore.reset(X509_STORE_new());
|
||||
|
||||
// Note: use "-system-" default here so that users can pass -rootcertificates=""
|
||||
// and get 'I don't like X.509 certificates, don't trust anybody' behavior:
|
||||
QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
|
||||
|
||||
// Empty store
|
||||
if (certFile.isEmpty()) {
|
||||
qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> certList;
|
||||
|
||||
if (certFile != "-system-") {
|
||||
qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
|
||||
|
||||
certList = QSslCertificate::fromPath(certFile);
|
||||
// Use those certificates when fetching payment requests, too:
|
||||
QSslSocket::setDefaultCaCertificates(certList);
|
||||
} else
|
||||
certList = QSslSocket::systemCaCertificates();
|
||||
|
||||
int nRootCerts = 0;
|
||||
const QDateTime currentTime = QDateTime::currentDateTime();
|
||||
|
||||
for (const QSslCertificate& cert : certList) {
|
||||
// Don't log NULL certificates
|
||||
if (cert.isNull())
|
||||
continue;
|
||||
|
||||
// Not yet active/valid, or expired certificate
|
||||
if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Blacklisted certificate
|
||||
if (cert.isBlacklisted()) {
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
QByteArray certData = cert.toDer();
|
||||
const unsigned char *data = (const unsigned char *)certData.data();
|
||||
|
||||
std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
|
||||
if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
|
||||
{
|
||||
// Note: X509_STORE increases the reference count to the X509 object,
|
||||
// we still have to release our reference to it.
|
||||
++nRootCerts;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
|
||||
|
||||
// Project for another day:
|
||||
// Fetch certificate revocation lists, and add them to certStore.
|
||||
// Issues to consider:
|
||||
// performance (start a thread to fetch in background?)
|
||||
// privacy (fetch through tor/proxy so IP address isn't revealed)
|
||||
// would it be easier to just use a compiled-in blacklist?
|
||||
// or use Qt's blacklist?
|
||||
// "certificate stapling" with server-side caching is more efficient
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Sending to the server is done synchronously, at startup.
|
||||
// If the server isn't already running, startup continues,
|
||||
|
@ -300,10 +195,10 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
|
|||
QObject(parent),
|
||||
saveURIs(true),
|
||||
uriServer(0),
|
||||
#ifdef ENABLE_BIP70
|
||||
netManager(0),
|
||||
#endif
|
||||
optionsModel(0)
|
||||
#ifdef ENABLE_BIP70
|
||||
,netManager(0)
|
||||
#endif
|
||||
{
|
||||
#ifdef ENABLE_BIP70
|
||||
// Verify that the version of the library that we linked against is
|
||||
|
@ -367,32 +262,6 @@ bool PaymentServer::eventFilter(QObject *object, QEvent *event)
|
|||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
void PaymentServer::initNetManager()
|
||||
{
|
||||
if (!optionsModel)
|
||||
return;
|
||||
delete netManager;
|
||||
|
||||
// netManager is used to fetch paymentrequests given in bitcoin: URIs
|
||||
netManager = new QNetworkAccessManager(this);
|
||||
|
||||
QNetworkProxy proxy;
|
||||
|
||||
// Query active SOCKS5 proxy
|
||||
if (optionsModel->getProxySettings(proxy)) {
|
||||
netManager->setProxy(proxy);
|
||||
|
||||
qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
|
||||
}
|
||||
else
|
||||
qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
|
||||
|
||||
connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished);
|
||||
connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PaymentServer::uiReady()
|
||||
{
|
||||
#ifdef ENABLE_BIP70
|
||||
|
@ -510,7 +379,140 @@ void PaymentServer::handleURIConnection()
|
|||
handleURIOrFile(msg);
|
||||
}
|
||||
|
||||
void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
|
||||
{
|
||||
this->optionsModel = _optionsModel;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
struct X509StoreDeleter {
|
||||
void operator()(X509_STORE* b) {
|
||||
X509_STORE_free(b);
|
||||
}
|
||||
};
|
||||
|
||||
struct X509Deleter {
|
||||
void operator()(X509* b) { X509_free(b); }
|
||||
};
|
||||
|
||||
namespace // Anon namespace
|
||||
{
|
||||
std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
|
||||
}
|
||||
|
||||
static void ReportInvalidCertificate(const QSslCertificate& cert)
|
||||
{
|
||||
qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
|
||||
}
|
||||
|
||||
//
|
||||
// Load OpenSSL's list of root certificate authorities
|
||||
//
|
||||
void PaymentServer::LoadRootCAs(X509_STORE* _store)
|
||||
{
|
||||
// Unit tests mostly use this, to pass in fake root CAs:
|
||||
if (_store)
|
||||
{
|
||||
certStore.reset(_store);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal execution, use either -rootcertificates or system certs:
|
||||
certStore.reset(X509_STORE_new());
|
||||
|
||||
// Note: use "-system-" default here so that users can pass -rootcertificates=""
|
||||
// and get 'I don't like X.509 certificates, don't trust anybody' behavior:
|
||||
QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
|
||||
|
||||
// Empty store
|
||||
if (certFile.isEmpty()) {
|
||||
qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QSslCertificate> certList;
|
||||
|
||||
if (certFile != "-system-") {
|
||||
qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
|
||||
|
||||
certList = QSslCertificate::fromPath(certFile);
|
||||
// Use those certificates when fetching payment requests, too:
|
||||
QSslSocket::setDefaultCaCertificates(certList);
|
||||
} else
|
||||
certList = QSslSocket::systemCaCertificates();
|
||||
|
||||
int nRootCerts = 0;
|
||||
const QDateTime currentTime = QDateTime::currentDateTime();
|
||||
|
||||
for (const QSslCertificate& cert : certList) {
|
||||
// Don't log NULL certificates
|
||||
if (cert.isNull())
|
||||
continue;
|
||||
|
||||
// Not yet active/valid, or expired certificate
|
||||
if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Blacklisted certificate
|
||||
if (cert.isBlacklisted()) {
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
|
||||
QByteArray certData = cert.toDer();
|
||||
const unsigned char *data = (const unsigned char *)certData.data();
|
||||
|
||||
std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
|
||||
if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
|
||||
{
|
||||
// Note: X509_STORE increases the reference count to the X509 object,
|
||||
// we still have to release our reference to it.
|
||||
++nRootCerts;
|
||||
}
|
||||
else
|
||||
{
|
||||
ReportInvalidCertificate(cert);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
|
||||
|
||||
// Project for another day:
|
||||
// Fetch certificate revocation lists, and add them to certStore.
|
||||
// Issues to consider:
|
||||
// performance (start a thread to fetch in background?)
|
||||
// privacy (fetch through tor/proxy so IP address isn't revealed)
|
||||
// would it be easier to just use a compiled-in blacklist?
|
||||
// or use Qt's blacklist?
|
||||
// "certificate stapling" with server-side caching is more efficient
|
||||
}
|
||||
|
||||
void PaymentServer::initNetManager()
|
||||
{
|
||||
if (!optionsModel)
|
||||
return;
|
||||
delete netManager;
|
||||
|
||||
// netManager is used to fetch paymentrequests given in bitcoin: URIs
|
||||
netManager = new QNetworkAccessManager(this);
|
||||
|
||||
QNetworkProxy proxy;
|
||||
|
||||
// Query active SOCKS5 proxy
|
||||
if (optionsModel->getProxySettings(proxy)) {
|
||||
netManager->setProxy(proxy);
|
||||
|
||||
qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
|
||||
}
|
||||
else
|
||||
qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
|
||||
|
||||
connect(netManager, &QNetworkAccessManager::finished, this, &PaymentServer::netRequestFinished);
|
||||
connect(netManager, &QNetworkAccessManager::sslErrors, this, &PaymentServer::reportSslErrors);
|
||||
}
|
||||
|
||||
//
|
||||
// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
|
||||
// so don't use "Q_EMIT message()", but "QMessageBox::"!
|
||||
|
@ -760,14 +762,7 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
|
|||
}
|
||||
Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
|
||||
}
|
||||
#endif
|
||||
|
||||
void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
|
||||
{
|
||||
this->optionsModel = _optionsModel;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
|
||||
{
|
||||
// currently we don't further process or store the paymentACK message
|
||||
|
|
|
@ -79,6 +79,9 @@ public:
|
|||
explicit PaymentServer(QObject* parent, bool startLocalServer = true);
|
||||
~PaymentServer();
|
||||
|
||||
// OptionsModel is used for getting proxy settings and display unit
|
||||
void setOptionsModel(OptionsModel *optionsModel);
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
// Load root certificate authorities. Pass nullptr (default)
|
||||
// to read from the file specified in the -rootcertificates setting,
|
||||
|
@ -89,12 +92,7 @@ public:
|
|||
|
||||
// Return certificate store
|
||||
static X509_STORE* getCertStore();
|
||||
#endif
|
||||
|
||||
// OptionsModel is used for getting proxy settings and display unit
|
||||
void setOptionsModel(OptionsModel *optionsModel);
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
// Verify that the payment request network matches the client network
|
||||
static bool verifyNetwork(interfaces::Node& node, const payments::PaymentDetails& requestDetails);
|
||||
// Verify if the payment request is expired
|
||||
|
@ -109,27 +107,27 @@ Q_SIGNALS:
|
|||
// Fired when a valid payment request is received
|
||||
void receivedPaymentRequest(SendCoinsRecipient);
|
||||
|
||||
// Fired when a message should be reported to the user
|
||||
void message(const QString &title, const QString &message, unsigned int style);
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
// Fired when a valid PaymentACK is received
|
||||
void receivedPaymentACK(const QString &paymentACKMsg);
|
||||
#endif
|
||||
|
||||
// Fired when a message should be reported to the user
|
||||
void message(const QString &title, const QString &message, unsigned int style);
|
||||
|
||||
public Q_SLOTS:
|
||||
// Signal this when the main window's UI is ready
|
||||
// to display payment requests to the user
|
||||
void uiReady();
|
||||
|
||||
// Handle an incoming URI, URI with local file scheme or file
|
||||
void handleURIOrFile(const QString& s);
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
// Submit Payment message to a merchant, get back PaymentACK:
|
||||
void fetchPaymentACK(WalletModel* walletModel, const SendCoinsRecipient& recipient, QByteArray transaction);
|
||||
#endif
|
||||
|
||||
// Handle an incoming URI, URI with local file scheme or file
|
||||
void handleURIOrFile(const QString& s);
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleURIConnection();
|
||||
#ifdef ENABLE_BIP70
|
||||
|
@ -144,6 +142,10 @@ protected:
|
|||
bool eventFilter(QObject *object, QEvent *event);
|
||||
|
||||
private:
|
||||
bool saveURIs; // true during startup
|
||||
QLocalServer* uriServer;
|
||||
OptionsModel *optionsModel;
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
|
||||
bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient);
|
||||
|
@ -151,16 +153,8 @@ private:
|
|||
|
||||
// Setup networking
|
||||
void initNetManager();
|
||||
#endif
|
||||
|
||||
bool saveURIs; // true during startup
|
||||
QLocalServer* uriServer;
|
||||
|
||||
#ifdef ENABLE_BIP70
|
||||
QNetworkAccessManager* netManager; // Used to fetch payment requests
|
||||
#endif
|
||||
|
||||
OptionsModel *optionsModel;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_QT_PAYMENTSERVER_H
|
||||
|
|
Loading…
Add table
Reference in a new issue