aboutsummaryrefslogtreecommitdiff
path: root/src/qt/paymentserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qt/paymentserver.cpp')
-rw-r--r--src/qt/paymentserver.cpp165
1 files changed, 86 insertions, 79 deletions
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 5f8a6bc37..88aaec8d3 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -10,7 +10,7 @@
#include "base58.h"
#include "chainparams.h"
-#include "main.h"
+#include "policy/policy.h"
#include "ui_interface.h"
#include "util.h"
#include "wallet/wallet.h"
@@ -46,28 +46,29 @@
#include <QUrlQuery>
#endif
-using namespace std;
-
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
-const QString BITCOIN_IPC_PREFIX("dogecoin:");
+const QString BITCOIN_IPC_PREFIX("bitcoin:");
// BIP70 payment protocol messages
const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK";
const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
// BIP71 payment protocol media types
-const char* BIP71_MIMETYPE_PAYMENT = "application/dogecoin-payment";
-const char* BIP71_MIMETYPE_PAYMENTACK = "application/dogecoin-paymentack";
-const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/dogecoin-paymentrequest";
-// BIP70 max payment request size in bytes (DoS protection)
-const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE = 50000;
-
-X509_STORE* PaymentServer::certStore = NULL;
-void PaymentServer::freeCertStore()
+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
{
- if (PaymentServer::certStore != NULL)
- {
- X509_STORE_free(PaymentServer::certStore);
- PaymentServer::certStore = NULL;
- }
+ std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
}
//
@@ -82,7 +83,7 @@ static QString ipcServerName()
// Append a simple hash of the datadir
// Note that GetDataDir(true) returns a different path
// for -testnet versus main net
- QString ddir(QString::fromStdString(GetDataDir(true).string()));
+ QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
name.append(QString::number(qHash(ddir)));
return name;
@@ -109,20 +110,15 @@ static void ReportInvalidCertificate(const QSslCertificate& cert)
//
void PaymentServer::LoadRootCAs(X509_STORE* _store)
{
- if (PaymentServer::certStore == NULL)
- atexit(PaymentServer::freeCertStore);
- else
- freeCertStore();
-
// Unit tests mostly use this, to pass in fake root CAs:
if (_store)
{
- PaymentServer::certStore = _store;
+ certStore.reset(_store);
return;
}
// Normal execution, use either -rootcertificates or system certs:
- PaymentServer::certStore = X509_STORE_new();
+ 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:
@@ -148,7 +144,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
- foreach (const QSslCertificate& cert, certList) {
+ Q_FOREACH (const QSslCertificate& cert, certList) {
// Don't log NULL certificates
if (cert.isNull())
continue;
@@ -169,11 +165,11 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
QByteArray certData = cert.toDer();
const unsigned char *data = (const unsigned char *)certData.data();
- X509* x509 = d2i_X509(0, &data, certData.size());
- if (x509 && X509_STORE_add_cert(PaymentServer::certStore, x509))
+ 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_free will free the X509* objects when
- // the PaymentServer is destroyed
+ // Note: X509_STORE increases the reference count to the X509 object,
+ // we still have to release our reference to it.
++nRootCerts;
}
else
@@ -201,7 +197,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// when uiReady() is called.
//
// Warning: ipcSendCommandLine() is called early in init,
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
@@ -269,7 +265,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
bool PaymentServer::ipcSendCommandLine()
{
bool fResult = false;
- foreach (const QString& r, savedPaymentRequests)
+ Q_FOREACH (const QString& r, savedPaymentRequests)
{
QLocalSocket* socket = new QLocalSocket();
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
@@ -326,7 +322,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
uriServer = new QLocalServer(this);
if (!uriServer->listen(name)) {
- // constructor is called early in init, so don't use "emit message()" here
+ // constructor is called early in init, so don't use "Q_EMIT message()" here
QMessageBox::critical(0, tr("Payment request error"),
tr("Cannot start dogecoin: click-to-pay handler"));
}
@@ -394,7 +390,7 @@ void PaymentServer::uiReady()
initNetManager();
saveURIs = false;
- foreach (const QString& s, savedPaymentRequests)
+ Q_FOREACH (const QString& s, savedPaymentRequests)
{
handleURIOrFile(s);
}
@@ -431,7 +427,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
else
{
qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
- emit message(tr("URI handling"),
+ Q_EMIT message(tr("URI handling"),
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING);
}
@@ -445,15 +441,15 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
CBitcoinAddress address(recipient.address.toStdString());
if (!address.IsValid()) {
- emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
+ Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
else
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
}
else
- emit message(tr("URI handling"),
- tr("URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
+ Q_EMIT message(tr("URI handling"),
+ tr("URI cannot be parsed! This can be caused by an invalid Dogecoin address or malformed URI parameters."),
CClientUIInterface::ICON_WARNING);
return;
@@ -466,12 +462,12 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (!readPaymentRequestFromFile(s, request))
{
- emit message(tr("Payment request file handling"),
+ Q_EMIT message(tr("Payment request file handling"),
tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
CClientUIInterface::ICON_WARNING);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -500,7 +496,7 @@ void PaymentServer::handleURIConnection()
//
// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
{
@@ -511,12 +507,7 @@ bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentR
}
// BIP70 DoS protection
- if (f.size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
- qWarning() << QString("PaymentServer::%1: Payment request %2 is too large (%3 bytes, allowed %4 bytes).")
- .arg(__func__)
- .arg(filename)
- .arg(f.size())
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
+ if (!verifySize(f.size())) {
return false;
}
@@ -533,7 +524,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
if (request.IsInitialized()) {
// Payment request network matches client network?
if (!verifyNetwork(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -542,13 +533,13 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Make sure any payment requests involved are still valid.
// This is re-checked just before sending coins in WalletModel::sendCoins().
if (verifyExpired(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request expired."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."),
CClientUIInterface::MSG_ERROR);
return false;
}
} else {
- emit message(tr("Payment request error"), tr("Payment request is not initialized."),
+ Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -557,12 +548,12 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.paymentRequest = request;
recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
- request.getMerchant(PaymentServer::certStore, recipient.authenticatedMerchant);
+ request.getMerchant(certStore.get(), recipient.authenticatedMerchant);
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
- foreach(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ Q_FOREACH(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
// Extract and check destination addresses
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
@@ -573,7 +564,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Unauthenticated payment requests to custom bitcoin addresses are not supported
// (there is no good way to tell the user where they are paying in a way they'd
// have a chance of understanding).
- emit message(tr("Payment request rejected"),
+ Q_EMIT message(tr("Payment request rejected"),
tr("Unverified payment requests to custom payment scripts are unsupported."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -583,14 +574,14 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range
// and no overflow has happened.
if (!verifyAmount(sendingTo.second)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
- if (txOut.IsDust(::minRelayTxFee)) {
- emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
+ if (txOut.IsDust(dustRelayFee)) {
+ Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR);
@@ -600,7 +591,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.amount += sendingTo.second;
// Also verify that the final amount is still in a valid range after adding additional amounts.
if (!verifyAmount(recipient.amount)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
}
@@ -647,7 +638,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
// Create a new refund address, or re-use:
QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant);
std::string strAccount = account.toStdString();
- set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
+ std::set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
if (!refundAddresses.empty()) {
CScript s = GetScriptForDestination(*refundAddresses.begin());
payments::Output* refund_to = payment.add_refund_to();
@@ -687,14 +678,13 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
reply->deleteLater();
// BIP70 DoS protection
- if (reply->size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
- QString msg = tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
- .arg(reply->request().url().toString())
- .arg(reply->size())
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
-
- qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg;
- emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR);
+ if (!verifySize(reply->size())) {
+ Q_EMIT message(tr("Payment request rejected"),
+ tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
+ .arg(reply->request().url().toString())
+ .arg(reply->size())
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE),
+ CClientUIInterface::MSG_ERROR);
return;
}
@@ -704,7 +694,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->errorString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -718,12 +708,12 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
if (!request.parse(data))
{
qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
- emit message(tr("Payment request error"),
+ Q_EMIT message(tr("Payment request error"),
tr("Payment request cannot be parsed!"),
CClientUIInterface::MSG_ERROR);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -736,11 +726,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->request().url().toString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
}
else
{
- emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
+ Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
}
}
}
@@ -750,22 +740,22 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_UNUSED(reply);
QString errString;
- foreach (const QSslError& err, errs) {
+ Q_FOREACH (const QSslError& err, errs) {
qWarning() << "PaymentServer::reportSslErrors: " << err;
errString += err.errorString() + "\n";
}
- emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
-void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
+void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
{
- this->optionsModel = optionsModel;
+ this->optionsModel = _optionsModel;
}
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
{
- // currently we don't futher process or store the paymentACK message
- emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
+ // currently we don't further process or store the paymentACK message
+ Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
}
bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
@@ -793,6 +783,18 @@ bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails
return fVerified;
}
+bool PaymentServer::verifySize(qint64 requestSize)
+{
+ bool fVerified = (requestSize <= BIP70_MAX_PAYMENTREQUEST_SIZE);
+ if (!fVerified) {
+ qWarning() << QString("PaymentServer::%1: Payment request too large (%2 bytes, allowed %3 bytes).")
+ .arg(__func__)
+ .arg(requestSize)
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
+ }
+ return fVerified;
+}
+
bool PaymentServer::verifyAmount(const CAmount& requestAmount)
{
bool fVerified = MoneyRange(requestAmount);
@@ -804,3 +806,8 @@ bool PaymentServer::verifyAmount(const CAmount& requestAmount)
}
return fVerified;
}
+
+X509_STORE* PaymentServer::getCertStore()
+{
+ return certStore.get();
+}