Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. // Copyright (c) 2011-2016 The Starwels developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #include "paymentserver.h"
  5. #include "starwelsunits.h"
  6. #include "guiutil.h"
  7. #include "optionsmodel.h"
  8. #include "base58.h"
  9. #include "chainparams.h"
  10. #include "policy/policy.h"
  11. #include "ui_interface.h"
  12. #include "util.h"
  13. #include "wallet/wallet.h"
  14. #include <cstdlib>
  15. #include <openssl/x509_vfy.h>
  16. #include <QApplication>
  17. #include <QByteArray>
  18. #include <QDataStream>
  19. #include <QDateTime>
  20. #include <QDebug>
  21. #include <QFile>
  22. #include <QFileOpenEvent>
  23. #include <QHash>
  24. #include <QList>
  25. #include <QLocalServer>
  26. #include <QLocalSocket>
  27. #include <QNetworkAccessManager>
  28. #include <QNetworkProxy>
  29. #include <QNetworkReply>
  30. #include <QNetworkRequest>
  31. #include <QSslCertificate>
  32. #include <QSslError>
  33. #include <QSslSocket>
  34. #include <QStringList>
  35. #include <QTextDocument>
  36. #if QT_VERSION < 0x050000
  37. #include <QUrl>
  38. #else
  39. #include <QUrlQuery>
  40. #endif
  41. const int STARWELS_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
  42. const QString STARWELS_IPC_PREFIX("starwels:");
  43. // BIP70 payment protocol messages
  44. const char* BIP70_MESSAGE_PAYMENTACK = "PaymentACK";
  45. const char* BIP70_MESSAGE_PAYMENTREQUEST = "PaymentRequest";
  46. // BIP71 payment protocol media types
  47. const char* BIP71_MIMETYPE_PAYMENT = "application/starwels-payment";
  48. const char* BIP71_MIMETYPE_PAYMENTACK = "application/starwels-paymentack";
  49. const char* BIP71_MIMETYPE_PAYMENTREQUEST = "application/starwels-paymentrequest";
  50. struct X509StoreDeleter {
  51. void operator()(X509_STORE* b) {
  52. X509_STORE_free(b);
  53. }
  54. };
  55. struct X509Deleter {
  56. void operator()(X509* b) { X509_free(b); }
  57. };
  58. namespace // Anon namespace
  59. {
  60. std::unique_ptr<X509_STORE, X509StoreDeleter> certStore;
  61. }
  62. //
  63. // Create a name that is unique for:
  64. // ai / non-ai
  65. // data directory
  66. //
  67. static QString ipcServerName()
  68. {
  69. QString name("StarwelsQt");
  70. // Append a simple hash of the datadir
  71. // Note that GetDataDir(true) returns a different path
  72. // for -ai versus main net
  73. QString ddir(GUIUtil::boostPathToQString(GetDataDir(true)));
  74. name.append(QString::number(qHash(ddir)));
  75. return name;
  76. }
  77. //
  78. // We store payment URIs and requests received before
  79. // the main GUI window is up and ready to ask the user
  80. // to send payment.
  81. static QList<QString> savedPaymentRequests;
  82. static void ReportInvalidCertificate(const QSslCertificate& cert)
  83. {
  84. #if QT_VERSION < 0x050000
  85. qDebug() << QString("%1: Payment server found an invalid certificate: ").arg(__func__) << cert.serialNumber() << cert.subjectInfo(QSslCertificate::CommonName) << cert.subjectInfo(QSslCertificate::OrganizationalUnitName);
  86. #else
  87. 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);
  88. #endif
  89. }
  90. //
  91. // Load OpenSSL's list of root certificate authorities
  92. //
  93. void PaymentServer::LoadRootCAs(X509_STORE* _store)
  94. {
  95. // Unit tests mostly use this, to pass in fake root CAs:
  96. if (_store)
  97. {
  98. certStore.reset(_store);
  99. return;
  100. }
  101. // Normal execution, use either -rootcertificates or system certs:
  102. certStore.reset(X509_STORE_new());
  103. // Note: use "-system-" default here so that users can pass -rootcertificates=""
  104. // and get 'I don't like X.509 certificates, don't trust anybody' behavior:
  105. QString certFile = QString::fromStdString(gArgs.GetArg("-rootcertificates", "-system-"));
  106. // Empty store
  107. if (certFile.isEmpty()) {
  108. qDebug() << QString("PaymentServer::%1: Payment request authentication via X.509 certificates disabled.").arg(__func__);
  109. return;
  110. }
  111. QList<QSslCertificate> certList;
  112. if (certFile != "-system-") {
  113. qDebug() << QString("PaymentServer::%1: Using \"%2\" as trusted root certificate.").arg(__func__).arg(certFile);
  114. certList = QSslCertificate::fromPath(certFile);
  115. // Use those certificates when fetching payment requests, too:
  116. QSslSocket::setDefaultCaCertificates(certList);
  117. } else
  118. certList = QSslSocket::systemCaCertificates();
  119. int nRootCerts = 0;
  120. const QDateTime currentTime = QDateTime::currentDateTime();
  121. for (const QSslCertificate& cert : certList) {
  122. // Don't log NULL certificates
  123. if (cert.isNull())
  124. continue;
  125. // Not yet active/valid, or expired certificate
  126. if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
  127. ReportInvalidCertificate(cert);
  128. continue;
  129. }
  130. #if QT_VERSION >= 0x050000
  131. // Blacklisted certificate
  132. if (cert.isBlacklisted()) {
  133. ReportInvalidCertificate(cert);
  134. continue;
  135. }
  136. #endif
  137. QByteArray certData = cert.toDer();
  138. const unsigned char *data = (const unsigned char *)certData.data();
  139. std::unique_ptr<X509, X509Deleter> x509(d2i_X509(0, &data, certData.size()));
  140. if (x509 && X509_STORE_add_cert(certStore.get(), x509.get()))
  141. {
  142. // Note: X509_STORE increases the reference count to the X509 object,
  143. // we still have to release our reference to it.
  144. ++nRootCerts;
  145. }
  146. else
  147. {
  148. ReportInvalidCertificate(cert);
  149. continue;
  150. }
  151. }
  152. qWarning() << "PaymentServer::LoadRootCAs: Loaded " << nRootCerts << " root certificates";
  153. // Project for another day:
  154. // Fetch certificate revocation lists, and add them to certStore.
  155. // Issues to consider:
  156. // performance (start a thread to fetch in background?)
  157. // privacy (fetch through tor/proxy so IP address isn't revealed)
  158. // would it be easier to just use a compiled-in blacklist?
  159. // or use Qt's blacklist?
  160. // "certificate stapling" with server-side caching is more efficient
  161. }
  162. //
  163. // Sending to the server is done synchronously, at startup.
  164. // If the server isn't already running, startup continues,
  165. // and the items in savedPaymentRequest will be handled
  166. // when uiReady() is called.
  167. //
  168. // Warning: ipcSendCommandLine() is called early in init,
  169. // so don't use "Q_EMIT message()", but "QMessageBox::"!
  170. //
  171. void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
  172. {
  173. for (int i = 1; i < argc; i++)
  174. {
  175. QString arg(argv[i]);
  176. if (arg.startsWith("-"))
  177. continue;
  178. // If the starwels: URI contains a payment request, we are not able to detect the
  179. // network as that would require fetching and parsing the payment request.
  180. // That means clicking such an URI which contains a ai payment request
  181. // will start a mainnet instance and throw a "wrong network" error.
  182. if (arg.startsWith(STARWELS_IPC_PREFIX, Qt::CaseInsensitive)) // starwels: URI
  183. {
  184. savedPaymentRequests.append(arg);
  185. SendCoinsRecipient r;
  186. if (GUIUtil::parseStarwelsURI(arg, &r) && !r.address.isEmpty())
  187. {
  188. CStarwelsAddress address(r.address.toStdString());
  189. auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN);
  190. if (address.IsValid(*tempChainParams))
  191. {
  192. SelectParams(CBaseChainParams::MAIN);
  193. }
  194. else {
  195. tempChainParams = CreateChainParams(CBaseChainParams::AI);
  196. if (address.IsValid(*tempChainParams))
  197. SelectParams(CBaseChainParams::AI);
  198. }
  199. }
  200. }
  201. else if (QFile::exists(arg)) // Filename
  202. {
  203. savedPaymentRequests.append(arg);
  204. PaymentRequestPlus request;
  205. if (readPaymentRequestFromFile(arg, request))
  206. {
  207. if (request.getDetails().network() == "main")
  208. {
  209. SelectParams(CBaseChainParams::MAIN);
  210. }
  211. else if (request.getDetails().network() == "test")
  212. {
  213. SelectParams(CBaseChainParams::AI);
  214. }
  215. }
  216. }
  217. else
  218. {
  219. // Printing to debug.log is about the best we can do here, the
  220. // GUI hasn't started yet so we can't pop up a message box.
  221. qWarning() << "PaymentServer::ipcSendCommandLine: Payment request file does not exist: " << arg;
  222. }
  223. }
  224. }
  225. //
  226. // Sending to the server is done synchronously, at startup.
  227. // If the server isn't already running, startup continues,
  228. // and the items in savedPaymentRequest will be handled
  229. // when uiReady() is called.
  230. //
  231. bool PaymentServer::ipcSendCommandLine()
  232. {
  233. bool fResult = false;
  234. for (const QString& r : savedPaymentRequests)
  235. {
  236. QLocalSocket* socket = new QLocalSocket();
  237. socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
  238. if (!socket->waitForConnected(STARWELS_IPC_CONNECT_TIMEOUT))
  239. {
  240. delete socket;
  241. socket = nullptr;
  242. return false;
  243. }
  244. QByteArray block;
  245. QDataStream out(&block, QIODevice::WriteOnly);
  246. out.setVersion(QDataStream::Qt_4_0);
  247. out << r;
  248. out.device()->seek(0);
  249. socket->write(block);
  250. socket->flush();
  251. socket->waitForBytesWritten(STARWELS_IPC_CONNECT_TIMEOUT);
  252. socket->disconnectFromServer();
  253. delete socket;
  254. socket = nullptr;
  255. fResult = true;
  256. }
  257. return fResult;
  258. }
  259. PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
  260. QObject(parent),
  261. saveURIs(true),
  262. uriServer(0),
  263. netManager(0),
  264. optionsModel(0)
  265. {
  266. // Verify that the version of the library that we linked against is
  267. // compatible with the version of the headers we compiled against.
  268. GOOGLE_PROTOBUF_VERIFY_VERSION;
  269. // Install global event filter to catch QFileOpenEvents
  270. // on Mac: sent when you click starwels: links
  271. // other OSes: helpful when dealing with payment request files
  272. if (parent)
  273. parent->installEventFilter(this);
  274. QString name = ipcServerName();
  275. // Clean up old socket leftover from a crash:
  276. QLocalServer::removeServer(name);
  277. if (startLocalServer)
  278. {
  279. uriServer = new QLocalServer(this);
  280. if (!uriServer->listen(name)) {
  281. // constructor is called early in init, so don't use "Q_EMIT message()" here
  282. QMessageBox::critical(0, tr("Payment request error"),
  283. tr("Cannot start starwels: click-to-pay handler"));
  284. }
  285. else {
  286. connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection()));
  287. connect(this, SIGNAL(receivedPaymentACK(QString)), this, SLOT(handlePaymentACK(QString)));
  288. }
  289. }
  290. }
  291. PaymentServer::~PaymentServer()
  292. {
  293. google::protobuf::ShutdownProtobufLibrary();
  294. }
  295. //
  296. // OSX-specific way of handling starwels: URIs and PaymentRequest mime types.
  297. // Also used by paymentservertests.cpp and when opening a payment request file
  298. // via "Open URI..." menu entry.
  299. //
  300. bool PaymentServer::eventFilter(QObject *object, QEvent *event)
  301. {
  302. if (event->type() == QEvent::FileOpen) {
  303. QFileOpenEvent *fileEvent = static_cast<QFileOpenEvent*>(event);
  304. if (!fileEvent->file().isEmpty())
  305. handleURIOrFile(fileEvent->file());
  306. else if (!fileEvent->url().isEmpty())
  307. handleURIOrFile(fileEvent->url().toString());
  308. return true;
  309. }
  310. return QObject::eventFilter(object, event);
  311. }
  312. void PaymentServer::initNetManager()
  313. {
  314. if (!optionsModel)
  315. return;
  316. if (netManager != nullptr)
  317. delete netManager;
  318. // netManager is used to fetch paymentrequests given in starwels: URIs
  319. netManager = new QNetworkAccessManager(this);
  320. QNetworkProxy proxy;
  321. // Query active SOCKS5 proxy
  322. if (optionsModel->getProxySettings(proxy)) {
  323. netManager->setProxy(proxy);
  324. qDebug() << "PaymentServer::initNetManager: Using SOCKS5 proxy" << proxy.hostName() << ":" << proxy.port();
  325. }
  326. else
  327. qDebug() << "PaymentServer::initNetManager: No active proxy server found.";
  328. connect(netManager, SIGNAL(finished(QNetworkReply*)),
  329. this, SLOT(netRequestFinished(QNetworkReply*)));
  330. connect(netManager, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> &)),
  331. this, SLOT(reportSslErrors(QNetworkReply*, const QList<QSslError> &)));
  332. }
  333. void PaymentServer::uiReady()
  334. {
  335. initNetManager();
  336. saveURIs = false;
  337. for (const QString& s : savedPaymentRequests)
  338. {
  339. handleURIOrFile(s);
  340. }
  341. savedPaymentRequests.clear();
  342. }
  343. void PaymentServer::handleURIOrFile(const QString& s)
  344. {
  345. if (saveURIs)
  346. {
  347. savedPaymentRequests.append(s);
  348. return;
  349. }
  350. if (s.startsWith(STARWELS_IPC_PREFIX, Qt::CaseInsensitive)) // starwels: URI
  351. {
  352. #if QT_VERSION < 0x050000
  353. QUrl uri(s);
  354. #else
  355. QUrlQuery uri((QUrl(s)));
  356. #endif
  357. if (uri.hasQueryItem("r")) // payment request URI
  358. {
  359. QByteArray temp;
  360. temp.append(uri.queryItemValue("r"));
  361. QString decoded = QUrl::fromPercentEncoding(temp);
  362. QUrl fetchUrl(decoded, QUrl::StrictMode);
  363. if (fetchUrl.isValid())
  364. {
  365. qDebug() << "PaymentServer::handleURIOrFile: fetchRequest(" << fetchUrl << ")";
  366. fetchRequest(fetchUrl);
  367. }
  368. else
  369. {
  370. qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
  371. Q_EMIT message(tr("URI handling"),
  372. tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
  373. CClientUIInterface::ICON_WARNING);
  374. }
  375. return;
  376. }
  377. else // normal URI
  378. {
  379. SendCoinsRecipient recipient;
  380. if (GUIUtil::parseStarwelsURI(s, &recipient))
  381. {
  382. CStarwelsAddress address(recipient.address.toStdString());
  383. if (!address.IsValid()) {
  384. Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
  385. CClientUIInterface::MSG_ERROR);
  386. }
  387. else
  388. Q_EMIT receivedPaymentRequest(recipient);
  389. }
  390. else
  391. Q_EMIT message(tr("URI handling"),
  392. tr("URI cannot be parsed! This can be caused by an invalid Starwels address or malformed URI parameters."),
  393. CClientUIInterface::ICON_WARNING);
  394. return;
  395. }
  396. }
  397. if (QFile::exists(s)) // payment request file
  398. {
  399. PaymentRequestPlus request;
  400. SendCoinsRecipient recipient;
  401. if (!readPaymentRequestFromFile(s, request))
  402. {
  403. Q_EMIT message(tr("Payment request file handling"),
  404. tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
  405. CClientUIInterface::ICON_WARNING);
  406. }
  407. else if (processPaymentRequest(request, recipient))
  408. Q_EMIT receivedPaymentRequest(recipient);
  409. return;
  410. }
  411. }
  412. void PaymentServer::handleURIConnection()
  413. {
  414. QLocalSocket *clientConnection = uriServer->nextPendingConnection();
  415. while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
  416. clientConnection->waitForReadyRead();
  417. connect(clientConnection, SIGNAL(disconnected()),
  418. clientConnection, SLOT(deleteLater()));
  419. QDataStream in(clientConnection);
  420. in.setVersion(QDataStream::Qt_4_0);
  421. if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
  422. return;
  423. }
  424. QString msg;
  425. in >> msg;
  426. handleURIOrFile(msg);
  427. }
  428. //
  429. // Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
  430. // so don't use "Q_EMIT message()", but "QMessageBox::"!
  431. //
  432. bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
  433. {
  434. QFile f(filename);
  435. if (!f.open(QIODevice::ReadOnly)) {
  436. qWarning() << QString("PaymentServer::%1: Failed to open %2").arg(__func__).arg(filename);
  437. return false;
  438. }
  439. // BIP70 DoS protection
  440. if (!verifySize(f.size())) {
  441. return false;
  442. }
  443. QByteArray data = f.readAll();
  444. return request.parse(data);
  445. }
  446. bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient)
  447. {
  448. if (!optionsModel)
  449. return false;
  450. if (request.IsInitialized()) {
  451. // Payment request network matches client network?
  452. if (!verifyNetwork(request.getDetails())) {
  453. Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
  454. CClientUIInterface::MSG_ERROR);
  455. return false;
  456. }
  457. // Make sure any payment requests involved are still valid.
  458. // This is re-checked just before sending coins in WalletModel::sendCoins().
  459. if (verifyExpired(request.getDetails())) {
  460. Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."),
  461. CClientUIInterface::MSG_ERROR);
  462. return false;
  463. }
  464. } else {
  465. Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."),
  466. CClientUIInterface::MSG_ERROR);
  467. return false;
  468. }
  469. recipient.paymentRequest = request;
  470. recipient.message = GUIUtil::HtmlEscape(request.getDetails().memo());
  471. request.getMerchant(certStore.get(), recipient.authenticatedMerchant);
  472. QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
  473. QStringList addresses;
  474. for (const std::pair<CScript, CAmount>& sendingTo : sendingTos) {
  475. // Extract and check destination addresses
  476. CTxDestination dest;
  477. if (ExtractDestination(sendingTo.first, dest)) {
  478. // Append destination address
  479. addresses.append(QString::fromStdString(CStarwelsAddress(dest).ToString()));
  480. }
  481. else if (!recipient.authenticatedMerchant.isEmpty()) {
  482. // Unauthenticated payment requests to custom starwels addresses are not supported
  483. // (there is no good way to tell the user where they are paying in a way they'd
  484. // have a chance of understanding).
  485. Q_EMIT message(tr("Payment request rejected"),
  486. tr("Unverified payment requests to custom payment scripts are unsupported."),
  487. CClientUIInterface::MSG_ERROR);
  488. return false;
  489. }
  490. // Starwels amounts are stored as (optional) uint64 in the protobuf messages (see paymentrequest.proto),
  491. // but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range
  492. // and no overflow has happened.
  493. if (!verifyAmount(sendingTo.second)) {
  494. Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
  495. return false;
  496. }
  497. // Extract and check amounts
  498. CTxOut txOut(sendingTo.second, sendingTo.first);
  499. if (IsDust(txOut, ::dustRelayFee)) {
  500. Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
  501. .arg(StarwelsUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
  502. CClientUIInterface::MSG_ERROR);
  503. return false;
  504. }
  505. recipient.amount += sendingTo.second;
  506. // Also verify that the final amount is still in a valid range after adding additional amounts.
  507. if (!verifyAmount(recipient.amount)) {
  508. Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
  509. return false;
  510. }
  511. }
  512. // Store addresses and format them to fit nicely into the GUI
  513. recipient.address = addresses.join("<br />");
  514. if (!recipient.authenticatedMerchant.isEmpty()) {
  515. qDebug() << "PaymentServer::processPaymentRequest: Secure payment request from " << recipient.authenticatedMerchant;
  516. }
  517. else {
  518. qDebug() << "PaymentServer::processPaymentRequest: Insecure payment request to " << addresses.join(", ");
  519. }
  520. return true;
  521. }
  522. void PaymentServer::fetchRequest(const QUrl& url)
  523. {
  524. QNetworkRequest netRequest;
  525. netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTREQUEST);
  526. netRequest.setUrl(url);
  527. netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
  528. netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTREQUEST);
  529. netManager->get(netRequest);
  530. }
  531. void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipient, QByteArray transaction)
  532. {
  533. const payments::PaymentDetails& details = recipient.paymentRequest.getDetails();
  534. if (!details.has_payment_url())
  535. return;
  536. QNetworkRequest netRequest;
  537. netRequest.setAttribute(QNetworkRequest::User, BIP70_MESSAGE_PAYMENTACK);
  538. netRequest.setUrl(QString::fromStdString(details.payment_url()));
  539. netRequest.setHeader(QNetworkRequest::ContentTypeHeader, BIP71_MIMETYPE_PAYMENT);
  540. netRequest.setRawHeader("User-Agent", CLIENT_NAME.c_str());
  541. netRequest.setRawHeader("Accept", BIP71_MIMETYPE_PAYMENTACK);
  542. payments::Payment payment;
  543. payment.set_merchant_data(details.merchant_data());
  544. payment.add_transactions(transaction.data(), transaction.size());
  545. // Create a new refund address, or re-use:
  546. QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant);
  547. std::string strAccount = account.toStdString();
  548. std::set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
  549. if (!refundAddresses.empty()) {
  550. CScript s = GetScriptForDestination(*refundAddresses.begin());
  551. payments::Output* refund_to = payment.add_refund_to();
  552. refund_to->set_script(&s[0], s.size());
  553. }
  554. else {
  555. CPubKey newKey;
  556. if (wallet->GetKeyFromPool(newKey)) {
  557. CKeyID keyID = newKey.GetID();
  558. wallet->SetAddressBook(keyID, strAccount, "refund");
  559. CScript s = GetScriptForDestination(keyID);
  560. payments::Output* refund_to = payment.add_refund_to();
  561. refund_to->set_script(&s[0], s.size());
  562. }
  563. else {
  564. // This should never happen, because sending coins should have
  565. // just unlocked the wallet and refilled the keypool.
  566. qWarning() << "PaymentServer::fetchPaymentACK: Error getting refund key, refund_to not set";
  567. }
  568. }
  569. int length = payment.ByteSize();
  570. netRequest.setHeader(QNetworkRequest::ContentLengthHeader, length);
  571. QByteArray serData(length, '\0');
  572. if (payment.SerializeToArray(serData.data(), length)) {
  573. netManager->post(netRequest, serData);
  574. }
  575. else {
  576. // This should never happen, either.
  577. qWarning() << "PaymentServer::fetchPaymentACK: Error serializing payment message";
  578. }
  579. }
  580. void PaymentServer::netRequestFinished(QNetworkReply* reply)
  581. {
  582. reply->deleteLater();
  583. // BIP70 DoS protection
  584. if (!verifySize(reply->size())) {
  585. Q_EMIT message(tr("Payment request rejected"),
  586. tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
  587. .arg(reply->request().url().toString())
  588. .arg(reply->size())
  589. .arg(BIP70_MAX_PAYMENTREQUEST_SIZE),
  590. CClientUIInterface::MSG_ERROR);
  591. return;
  592. }
  593. if (reply->error() != QNetworkReply::NoError) {
  594. QString msg = tr("Error communicating with %1: %2")
  595. .arg(reply->request().url().toString())
  596. .arg(reply->errorString());
  597. qWarning() << "PaymentServer::netRequestFinished: " << msg;
  598. Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
  599. return;
  600. }
  601. QByteArray data = reply->readAll();
  602. QString requestType = reply->request().attribute(QNetworkRequest::User).toString();
  603. if (requestType == BIP70_MESSAGE_PAYMENTREQUEST)
  604. {
  605. PaymentRequestPlus request;
  606. SendCoinsRecipient recipient;
  607. if (!request.parse(data))
  608. {
  609. qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
  610. Q_EMIT message(tr("Payment request error"),
  611. tr("Payment request cannot be parsed!"),
  612. CClientUIInterface::MSG_ERROR);
  613. }
  614. else if (processPaymentRequest(request, recipient))
  615. Q_EMIT receivedPaymentRequest(recipient);
  616. return;
  617. }
  618. else if (requestType == BIP70_MESSAGE_PAYMENTACK)
  619. {
  620. payments::PaymentACK paymentACK;
  621. if (!paymentACK.ParseFromArray(data.data(), data.size()))
  622. {
  623. QString msg = tr("Bad response from server %1")
  624. .arg(reply->request().url().toString());
  625. qWarning() << "PaymentServer::netRequestFinished: " << msg;
  626. Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
  627. }
  628. else
  629. {
  630. Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
  631. }
  632. }
  633. }
  634. void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError> &errs)
  635. {
  636. Q_UNUSED(reply);
  637. QString errString;
  638. for (const QSslError& err : errs) {
  639. qWarning() << "PaymentServer::reportSslErrors: " << err;
  640. errString += err.errorString() + "\n";
  641. }
  642. Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
  643. }
  644. void PaymentServer::setOptionsModel(OptionsModel *_optionsModel)
  645. {
  646. this->optionsModel = _optionsModel;
  647. }
  648. void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
  649. {
  650. // currently we don't further process or store the paymentACK message
  651. Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
  652. }
  653. bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
  654. {
  655. bool fVerified = requestDetails.network() == Params().NetworkIDString();
  656. if (!fVerified) {
  657. qWarning() << QString("PaymentServer::%1: Payment request network \"%2\" doesn't match client network \"%3\".")
  658. .arg(__func__)
  659. .arg(QString::fromStdString(requestDetails.network()))
  660. .arg(QString::fromStdString(Params().NetworkIDString()));
  661. }
  662. return fVerified;
  663. }
  664. bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails)
  665. {
  666. bool fVerified = (requestDetails.has_expires() && (int64_t)requestDetails.expires() < GetTime());
  667. if (fVerified) {
  668. const QString requestExpires = QString::fromStdString(DateTimeStrFormat("%Y-%m-%d %H:%M:%S", (int64_t)requestDetails.expires()));
  669. qWarning() << QString("PaymentServer::%1: Payment request expired \"%2\".")
  670. .arg(__func__)
  671. .arg(requestExpires);
  672. }
  673. return fVerified;
  674. }
  675. bool PaymentServer::verifySize(qint64 requestSize)
  676. {
  677. bool fVerified = (requestSize <= BIP70_MAX_PAYMENTREQUEST_SIZE);
  678. if (!fVerified) {
  679. qWarning() << QString("PaymentServer::%1: Payment request too large (%2 bytes, allowed %3 bytes).")
  680. .arg(__func__)
  681. .arg(requestSize)
  682. .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
  683. }
  684. return fVerified;
  685. }
  686. bool PaymentServer::verifyAmount(const CAmount& requestAmount)
  687. {
  688. bool fVerified = MoneyRange(requestAmount);
  689. if (!fVerified) {
  690. qWarning() << QString("PaymentServer::%1: Payment request amount out of allowed range (%2, allowed 0 - %3).")
  691. .arg(__func__)
  692. .arg(requestAmount)
  693. .arg(MAX_MONEY);
  694. }
  695. return fVerified;
  696. }
  697. X509_STORE* PaymentServer::getCertStore()
  698. {
  699. return certStore.get();
  700. }