8#include <chainparams.h>
21#include <openssl/x509_vfy.h>
24#include <QApplication>
30#include <QFileOpenEvent>
33#include <QLocalServer>
34#include <QLocalSocket>
36#include <QNetworkAccessManager>
37#include <QNetworkProxy>
38#include <QNetworkReply>
39#include <QNetworkRequest>
40#include <QSslCertificate>
41#include <QSslConfiguration>
45#include <QTextDocument>
88 if (!
arg.startsWith(
scheme +
":", Qt::CaseInsensitive)) {
101 const std::string &network) {
108 const std::string &network) {
123 std::array<const std::string *, 3>
networks = {
129 for (
int i = 1; i <
argc; i++) {
131 if (
arg.startsWith(
"-")) {
167 qWarning() <<
"PaymentServer::ipcSendCommandLine: Payment request "
168 "file or URI does not exist or is invalid: "
175 qWarning() <<
"PaymentServer::ipcSendCommandLine: Payment request "
178 <<
" does not match already chosen network "
214 out.setVersion(QDataStream::Qt_4_0);
216 out.device()->seek(0);
221 socket->disconnectFromServer();
249 parent->installEventFilter(
this);
255 QLocalServer::removeServer(
name);
263 QMessageBox::critical(
nullptr,
tr(
"Payment request error"),
264 tr(
"Cannot start click-to-pay handler"));
269 connect(
this, &PaymentServer::receivedPaymentACK,
this,
270 &PaymentServer::handlePaymentACK);
278 google::protobuf::ShutdownProtobufLibrary();
288 if (event->type() == QEvent::FileOpen) {
292 }
else if (!
fileEvent->url().isEmpty()) {
299 return QObject::eventFilter(
object, event);
316 if (!s.startsWith(
scheme +
":", Qt::CaseInsensitive)) {
323 if (
uri.hasQueryItem(
"r")) {
325 temp.append(
uri.queryItemValue(
"r").toUtf8());
330 qDebug() <<
"PaymentServer::handleURIOrFile: fetchRequest("
334 qWarning() <<
"PaymentServer::handleURIOrFile: Invalid URL: "
337 tr(
"Payment request fetch URL is invalid: %1")
352 if (
uri.hasQueryItem(
"r")) {
354 tr(
"Cannot process payment request because "
355 "BIP70 support was not compiled in."),
361 tr(
"Invalid payment address %1").
arg(recipient.
address),
369 tr(
"URI cannot be parsed! This can be caused by an invalid "
370 "Bitcoin address or malformed URI parameters."),
389 if (QFile::exists(s)) {
395 tr(
"Payment request file cannot be read! This can "
396 "be caused by an invalid payment request file."),
405 tr(
"Cannot process payment request because BIP70 "
406 "support was not compiled in."),
420 &QLocalSocket::deleteLater);
423 in.setVersion(QDataStream::Qt_4_0);
448std::unique_ptr<X509_STORE, X509StoreDeleter>
certStore;
452 qDebug() <<
QString(
"%1: Payment server found an invalid certificate: ")
454 <<
cert.serialNumber()
455 <<
cert.subjectInfo(QSslCertificate::CommonName)
456 <<
cert.subjectInfo(QSslCertificate::DistinguishedNameQualifier)
457 <<
cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
477 QString::fromStdString(
gArgs.
GetArg(
"-rootcertificates",
"-system-"));
481 qDebug() <<
QString(
"PaymentServer::%1: Payment request authentication "
482 "via X.509 certificates disabled.")
490 qDebug() <<
QString(
"PaymentServer::%1: Using \"%2\" as trusted root "
497 QSslConfiguration::defaultConfiguration().setCaCertificates(
certList);
499 certList = QSslConfiguration::systemCaCertificates();
519 if (
cert.isBlacklisted()) {
527 std::unique_ptr<X509, X509Deleter>
x509(
539 <<
" root certificates";
551void PaymentServer::initNetManager() {
568 qDebug() <<
"PaymentServer::initNetManager: Using SOCKS5 proxy"
569 << proxy.hostName() <<
":" << proxy.port();
572 <<
"PaymentServer::initNetManager: No active proxy server found.";
576 &PaymentServer::netRequestFinished);
578 &PaymentServer::reportSslErrors);
585bool PaymentServer::readPaymentRequestFromFile(
const QString &filename,
588 if (!
f.open(QIODevice::ReadOnly)) {
602 return request.
parse(data);
615 tr(
"Payment request rejected"),
616 tr(
"Payment request network doesn't match client network."),
627 tr(
"Payment request expired."),
634 tr(
"Payment request is not initialized."),
640 recipient.paymentRequest = request;
660 tr(
"Unverified payment requests to custom payment "
661 "scripts are unsupported."),
672 tr(
"Invalid payment request."),
681 tr(
"Payment request error"),
682 tr(
"Requested payment amount of %1 is too small (considered "
696 tr(
"Invalid payment request."),
705 qDebug() <<
"PaymentServer::processPaymentRequest: Secure payment "
709 qDebug() <<
"PaymentServer::processPaymentRequest: Insecure payment "
717void PaymentServer::dataDownloaded() {
719 qWarning() <<
"PaymentServer::dataDownloaded: Payment request size "
720 "bigger than expected - aborting";
728void PaymentServer::fetchRequest(
const QUrl &
url) {
730 netRequest.setAttribute(QNetworkRequest::User,
746 &PaymentServer::dataDownloaded);
752 const payments::PaymentDetails &details =
753 recipient.paymentRequest.getDetails();
754 if (!details.has_payment_url()) {
760 netRequest.setUrl(QString::fromStdString(details.payment_url()));
761 netRequest.setHeader(QNetworkRequest::ContentTypeHeader,
767 payment.set_merchant_data(details.merchant_data());
779 std::string label =
tr(
"Refund from %1")
782 wallet.setAddressBook(dest, label,
"refund");
790 qWarning() <<
"PaymentServer::fetchPaymentACK: Error getting refund "
791 "key, refund_to not set";
795#ifdef USE_PROTOBUF_MESSAGE_BYTESIZELONG
807 qWarning() <<
"PaymentServer::fetchPaymentACK: Error serializing "
812void PaymentServer::netRequestFinished(
QNetworkReply *reply) {
813 reply->deleteLater();
822 tr(
"Payment request rejected"),
823 tr(
"Payment request %1 is larger than the max allowed %2 bytes).")
824 .
arg(reply->request().url().toString())
830 if (reply->error() != QNetworkReply::NoError) {
831 QString msg =
tr(
"Error communicating with %1: %2")
832 .arg(reply->request().url().toString())
833 .arg(reply->errorString());
835 qWarning() <<
"PaymentServer::netRequestFinished: " << msg;
844 reply->request().attribute(QNetworkRequest::User).toString();
848 if (!request.
parse(data)) {
849 qWarning() <<
"PaymentServer::netRequestFinished: Error parsing "
852 tr(
"Payment request cannot be parsed!"),
861 if (!
paymentACK.ParseFromArray(data.data(), data.size())) {
862 QString msg =
tr(
"Bad response from server %1")
863 .arg(reply->request().url().toString());
865 qWarning() <<
"PaymentServer::netRequestFinished: " << msg;
880 qWarning() <<
"PaymentServer::reportSslErrors: " <<
err;
894bool PaymentServer::verifyNetwork(
901 "\"%2\" doesn't match client network \"%3\".")
909bool PaymentServer::verifyExpired(
917 "PaymentServer::%1: Payment request expired \"%2\".")
928 "(downloaded %2 bytes, max allowed %3 bytes).")
940 "of allowed range (%2, allowed 0 - %3).")
bool MoneyRange(const Amount nValue)
static constexpr Amount SATOSHI
static constexpr Amount MAX_MONEY
No amount larger than this (in satoshi) is valid.
std::string EncodeCashAddr(const CTxDestination &dst, const CChainParams ¶ms)
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given BIP70 chain name.
std::unique_ptr< const CChainParams > CreateChainParams(const ArgsManager &args, const std::string &chain)
Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
const CChainParams & Params()
Return the currently selected parameters.
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
static QString formatWithUnit(int unit, const Amount amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD)
Format as string (with unit)
static const std::string REGTEST
static const std::string TESTNET
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
const std::string & CashAddrPrefix() const
@ MODAL
Force blocking, modal message box dialog (not just OS notification)
Serialized script, used inside transaction inputs and outputs.
An output of a transaction.
virtual const CChainParams & GetChainParams() const =0
Interface from Qt to configuration data structure for Bitcoin client.
int getDisplayUnit() const
bool getProxySettings(QNetworkProxy &proxy) const
interfaces::Node & node() const
QList< std::pair< CScript, Amount > > getPayTo() const
bool getMerchant(X509_STORE *certStore, QString &merchant) const
bool IsInitialized() const
bool parse(const QByteArray &data)
const payments::PaymentDetails & getDetails() const
static bool ipcSendCommandLine()
void setOptionsModel(OptionsModel *optionsModel)
PaymentServer(QObject *parent, bool startLocalServer=true)
void message(const QString &title, const QString &message, unsigned int style)
void handleURIConnection()
static void ipcParseCommandLine(int argc, char *argv[])
void receivedPaymentRequest(SendCoinsRecipient)
bool eventFilter(QObject *object, QEvent *event) override
void handleURIOrFile(const QString &s)
bool handleURI(const CChainParams ¶ms, const QString &s)
OptionsModel * optionsModel
QString authenticatedMerchant
Top-level interface for a bitcoin node (bitcoind process).
virtual CFeeRate getDustRelayFee()=0
Get dust relay fee.
Interface for accessing a wallet.
const std::string CLIENT_NAME
const Config & GetConfig()
bool IsValidDestinationString(const std::string &str, const CChainParams ¶ms)
bool parseBitcoinURI(const QString &scheme, const QUrl &uri, SendCoinsRecipient *out)
QString HtmlEscape(const QString &str, bool fMultiLine)
QString boostPathToQString(const fs::path &path)
Convert OS specific boost path to QString through UTF-8.
static QString ipcServerName()
static bool ipcCanParseLegacyURI(const QString &arg, const std::string &network)
const int BITCOIN_IPC_CONNECT_TIMEOUT
static std::string ipcParseURI(const QString &arg, const CChainParams ¶ms, bool useCashAddr)
static bool ipcCanParseCashAddrURI(const QString &arg, const std::string &network)
static QSet< QString > savedPaymentRequests
static QT_END_NAMESPACE const qint64 BIP70_MAX_PAYMENTREQUEST_SIZE
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.