qt: cleanup: Move BIP70 functions together in paymentserver

Reduces the number of separate `#ifdefs` spans.
This commit is contained in:
Wladimir J. van der Laan 2017-11-09 16:41:15 +01:00 committed by James Hilliard
parent 9dcf6c0dfe
commit 38b98507cd
2 changed files with 149 additions and 160 deletions

View file

@ -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

View file

@ -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