PIVX Core  5.6.99
P2P Digital Currency
paymentserver.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2014 The Bitcoin developers
2 // Copyright (c) 2014-2015 The Dash developers
3 // Copyright (c) 2015-2021 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "paymentserver.h"
8 
9 #include "guiutil.h"
10 #include "optionsmodel.h"
11 
12 #include "key_io.h"
13 #include "chainparams.h"
14 #include "guiinterface.h"
15 #include "util/system.h"
16 
17 #include <QApplication>
18 #include <QByteArray>
19 #include <QDataStream>
20 #include <QDateTime>
21 #include <QFileOpenEvent>
22 #include <QLocalServer>
23 #include <QLocalSocket>
24 #include <QStringList>
25 #include <QUrlQuery>
26 
27 
28 const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
29 const QString BITCOIN_IPC_PREFIX("pivx:");
30 
31 //
32 // Create a name that is unique for:
33 // testnet / non-testnet
34 // data directory
35 //
36 static QString ipcServerName()
37 {
38  QString name("PIVXQt");
39 
40  // Append a simple hash of the datadir
41  // Note that GetDataDir(true) returns a different path
42  // for -testnet versus main net
43  QString ddir(QString::fromStdString(GetDataDir(true).string()));
44  name.append(QString::number(qHash(ddir)));
45 
46  return name;
47 }
48 
49 //
50 // We store payment URIs and requests received before
51 // the main GUI window is up and ready to ask the user
52 // to send payment.
53 
54 static QList<QString> savedPaymentRequests;
55 
56 //
57 // Sending to the server is done synchronously, at startup.
58 // If the server isn't already running, startup continues,
59 // and the items in savedPaymentRequest will be handled
60 // when uiReady() is called.
61 //
62 // Warning: ipcSendCommandLine() is called early in init,
63 // so don't use "emit message()", but "QMessageBox::"!
64 //
66 {
67  for (int i = 1; i < argc; i++) {
68  QString arg(argv[i]);
69  if (arg.startsWith("-"))
70  continue;
71 
72  // If the pivx: URI contains a payment request, we are not able to detect the
73  // network as that would require fetching and parsing the payment request.
74  // That means clicking such an URI which contains a testnet payment request
75  // will start a mainnet instance and throw a "wrong network" error.
76  if (arg.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // pivx: URI
77  {
78  savedPaymentRequests.append(arg);
79 
81  if (GUIUtil::parseBitcoinURI(arg, &r) && !r.address.isEmpty()) {
84  } else if (IsValidDestinationString(r.address.toStdString(), false, *CreateChainParams(CBaseChainParams::TESTNET))) {
86  }
87  }
88  }
89  }
90 }
91 
92 //
93 // Sending to the server is done synchronously, at startup.
94 // If the server isn't already running, startup continues,
95 // and the items in savedPaymentRequest will be handled
96 // when uiReady() is called.
97 //
99 {
100  bool fResult = false;
101  for (const QString& r : savedPaymentRequests) {
102  QLocalSocket* socket = new QLocalSocket();
103  socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
104  if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT)) {
105  delete socket;
106  socket = nullptr;
107  return false;
108  }
109 
110  QByteArray block;
111  QDataStream out(&block, QIODevice::WriteOnly);
112  out.setVersion(QDataStream::Qt_4_0);
113  out << r;
114  out.device()->seek(0);
115 
116  socket->write(block);
117  socket->flush();
118  socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);
119  socket->disconnectFromServer();
120 
121  delete socket;
122  socket = nullptr;
123  fResult = true;
124  }
125 
126  return fResult;
127 }
128 
129 PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) : QObject(parent),
130  saveURIs(true),
131  uriServer(0),
132  optionsModel(0)
133 {
134  // Install global event filter to catch QFileOpenEvents
135  // on Mac: sent when you click pivx: links
136  // other OSes: helpful when dealing with payment request files (in the future)
137  if (parent)
138  parent->installEventFilter(this);
139 
140  QString name = ipcServerName();
141 
142  // Clean up old socket leftover from a crash:
143  QLocalServer::removeServer(name);
144 
145  if (startLocalServer) {
146  uriServer = new QLocalServer(this);
147 
148  if (!uriServer->listen(name)) {
149  // constructor is called early in init, so don't use "emit message()" here
150  QMessageBox::critical(0, tr("Payment request error"),
151  tr("Cannot start pivx: click-to-pay handler"));
152  } else {
153  connect(uriServer, &QLocalServer::newConnection, this, &PaymentServer::handleURIConnection);
154  }
155  }
156 }
157 
159 {
160 }
161 
162 //
163 // OSX-specific way of handling pivx: URIs
164 //
165 bool PaymentServer::eventFilter(QObject* object, QEvent* event)
166 {
167  // clicking on pivx: URIs creates FileOpen events on the Mac
168  if (event->type() == QEvent::FileOpen) {
169  QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
170  if (!fileEvent->file().isEmpty())
171  handleURIOrFile(fileEvent->file());
172  else if (!fileEvent->url().isEmpty())
173  handleURIOrFile(fileEvent->url().toString());
174 
175  return true;
176  }
177 
178  return QObject::eventFilter(object, event);
179 }
180 
182 {
183  saveURIs = false;
184  for (const QString& s : savedPaymentRequests) {
185  handleURIOrFile(s);
186  }
187  savedPaymentRequests.clear();
188 }
189 
190 void PaymentServer::handleURIOrFile(const QString& s)
191 {
192  if (saveURIs) {
193  savedPaymentRequests.append(s);
194  return;
195  }
196 
197  if (s.startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive)) // pivx: URI
198  {
199  QUrlQuery uri((QUrl(s)));
200  // normal URI
201  {
202  SendCoinsRecipient recipient;
203  if (GUIUtil::parseBitcoinURI(s, &recipient)) {
204  if (!IsValidDestinationString(recipient.address.toStdString(), false, Params())) {
205  Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
207  } else
208  Q_EMIT receivedPaymentRequest(recipient);
209  } else
210  Q_EMIT message(tr("URI handling"),
211  tr("URI cannot be parsed! This can be caused by an invalid PIVX address or malformed URI parameters."),
213 
214  return;
215  }
216  }
217 }
218 
220 {
221  QLocalSocket* clientConnection = uriServer->nextPendingConnection();
222 
223  while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
224  clientConnection->waitForReadyRead();
225 
226  connect(clientConnection, &QLocalSocket::disconnected, clientConnection, &QLocalSocket::deleteLater);
227 
228  QDataStream in(clientConnection);
229  in.setVersion(QDataStream::Qt_4_0);
230  if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
231  return;
232  }
233  QString msg;
234  in >> msg;
235 
236  handleURIOrFile(msg);
237 }
238 
240 {
241  this->optionsModel = optionsModel;
242 }
true
Definition: bls_dkg.cpp:153
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given chain name.
const CChainParams & Params()
Return the currently selected parameters.
std::unique_ptr< CChainParams > CreateChainParams(const std::string &chain)
Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
static const std::string TESTNET
static const std::string MAIN
Chain name strings.
Interface from Qt to configuration data structure for PIVX client.
Definition: optionsmodel.h:22
static bool ipcSendCommandLine()
void receivedPaymentRequest(const SendCoinsRecipient &recipient)
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[])
QLocalServer * uriServer
Definition: paymentserver.h:99
void handleURIOrFile(const QString &s)
bool eventFilter(QObject *object, QEvent *event)
OptionsModel * optionsModel
char ** argv
Definition: fuzz.cpp:52
bool IsValidDestinationString(const std::string &str, bool fStaking, const CChainParams &params)
Definition: key_io.cpp:113
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
Definition: guiutil.cpp:156
const int BITCOIN_IPC_CONNECT_TIMEOUT
const QString BITCOIN_IPC_PREFIX("pivx:")
const char * name
Definition: rest.cpp:37
const fs::path & GetDataDir(bool fNetSpecific)
Definition: system.cpp:724