Changeset View
Changeset View
Standalone View
Standalone View
src/qt/paymentserver.cpp
Show All 11 Lines | |||||
#include "config.h" | #include "config.h" | ||||
#include "dstencode.h" | #include "dstencode.h" | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "ui_interface.h" | #include "ui_interface.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "wallet/wallet.h" | #include "wallet/wallet.h" | ||||
#include <cstdlib> | #include <cstdlib> | ||||
#include <tuple> | |||||
#include <openssl/x509_vfy.h> | #include <openssl/x509_vfy.h> | ||||
#include <QApplication> | #include <QApplication> | ||||
#include <QByteArray> | #include <QByteArray> | ||||
#include <QDataStream> | #include <QDataStream> | ||||
#include <QDateTime> | #include <QDateTime> | ||||
#include <QDebug> | #include <QDebug> | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | #endif | ||||
// Issues to consider: | // Issues to consider: | ||||
// performance (start a thread to fetch in background?) | // performance (start a thread to fetch in background?) | ||||
// privacy (fetch through tor/proxy so IP address isn't revealed) | // privacy (fetch through tor/proxy so IP address isn't revealed) | ||||
// would it be easier to just use a compiled-in blacklist? | // would it be easier to just use a compiled-in blacklist? | ||||
// or use Qt's blacklist? | // or use Qt's blacklist? | ||||
// "certificate stapling" with server-side caching is more efficient | // "certificate stapling" with server-side caching is more efficient | ||||
} | } | ||||
static std::pair<bool, std::string> ipcParseURI(const QString &arg) { | |||||
std::vector<std::string> networks = {CBaseChainParams::MAIN, | |||||
CBaseChainParams::TESTNET, | |||||
CBaseChainParams::REGTEST}; | |||||
for (std::string net : networks) { | |||||
const CChainParams ¶ms(Params(net)); | |||||
const QString scheme = GUIUtil::bitcoinURIScheme(params, true); | |||||
if (!arg.startsWith(scheme + ":", Qt::CaseInsensitive)) { | |||||
continue; | |||||
} | |||||
SendCoinsRecipient r; | |||||
if (!GUIUtil::parseBitcoinURI(scheme, arg, &r)) { | |||||
return {false, std::string{}}; | |||||
} | |||||
if (!IsValidDestinationString(r.address.toStdString(), params)) { | |||||
return {false, std::string{}}; | |||||
} | |||||
savedPaymentRequests.append(arg); | |||||
return {true, net}; | |||||
} | |||||
return {false, std::string{}}; | |||||
} | |||||
// | // | ||||
// Sending to the server is done synchronously, at startup. | // Sending to the server is done synchronously, at startup. | ||||
// If the server isn't already running, startup continues, and the items in | // If the server isn't already running, startup continues, and the items in | ||||
// savedPaymentRequest will be handled when uiReady() is called. | // savedPaymentRequest will be handled when uiReady() is called. | ||||
// | // | ||||
// Warning: ipcSendCommandLine() is called early in init, so don't use "Q_EMIT | // Warning: ipcSendCommandLine() is called early in init, so don't use "Q_EMIT | ||||
// message()", but "QMessageBox::"! | // message()", but "QMessageBox::"! | ||||
// | // | ||||
void PaymentServer::ipcParseCommandLine(int argc, char *argv[]) { | std::string PaymentServer::ipcParseCommandLine(int argc, char *argv[]) { | ||||
std::string network; | |||||
for (int i = 1; i < argc; i++) { | for (int i = 1; i < argc; i++) { | ||||
QString arg(argv[i]); | QString arg(argv[i]); | ||||
if (arg.startsWith("-")) continue; | if (arg.startsWith("-")) continue; | ||||
QString scheme = GUIUtil::bitcoinURIScheme(Params(), false); | bool parseOK; | ||||
// If the bitcoincash: URI contains a payment request, we are not able | std::tie(parseOK, network) = ipcParseURI(arg); | ||||
// to detect the network as that would require fetching and parsing the | if (parseOK) { | ||||
// payment request. That means clicking such an URI which contains a | continue; | ||||
// testnet payment request will start a mainnet instance and throw a | |||||
// "wrong network" error. | |||||
if (arg.startsWith(scheme + ":", | |||||
Qt::CaseInsensitive)) // bitcoincash: URI | |||||
{ | |||||
savedPaymentRequests.append(arg); | |||||
SendCoinsRecipient r; | |||||
if (GUIUtil::parseBitcoinURI(scheme, arg, &r) && | |||||
!r.address.isEmpty()) { | |||||
if (IsValidDestinationString(r.address.toStdString(), | |||||
Params(CBaseChainParams::MAIN))) { | |||||
SelectParams(CBaseChainParams::MAIN); | |||||
} else if (IsValidDestinationString( | |||||
r.address.toStdString(), | |||||
Params(CBaseChainParams::TESTNET))) { | |||||
SelectParams(CBaseChainParams::TESTNET); | |||||
} | |||||
} | |||||
} else if (QFile::exists(arg)) { | } else if (QFile::exists(arg)) { | ||||
// Filename | // Filename | ||||
savedPaymentRequests.append(arg); | savedPaymentRequests.append(arg); | ||||
PaymentRequestPlus request; | PaymentRequestPlus request; | ||||
if (readPaymentRequestFromFile(arg, request)) { | if (readPaymentRequestFromFile(arg, request)) { | ||||
if (request.getDetails().network() == "main") { | if (request.getDetails().network() == "main") { | ||||
SelectParams(CBaseChainParams::MAIN); | SelectParams(CBaseChainParams::MAIN); | ||||
} else if (request.getDetails().network() == "test") { | } else if (request.getDetails().network() == "test") { | ||||
SelectParams(CBaseChainParams::TESTNET); | SelectParams(CBaseChainParams::TESTNET); | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
// Printing to debug.log is about the best we can do here, the GUI | // Printing to debug.log is about the best we can do here, the GUI | ||||
// hasn't started yet so we can't pop up a message box. | // hasn't started yet so we can't pop up a message box. | ||||
qWarning() << "PaymentServer::ipcSendCommandLine: Payment request " | qWarning() << "PaymentServer::ipcSendCommandLine: Payment request " | ||||
"file does not exist: " | "file does not exist: " | ||||
<< arg; | << arg; | ||||
} | } | ||||
} | } | ||||
return network; | |||||
} | } | ||||
// | // | ||||
// Sending to the server is done synchronously, at startup. | // Sending to the server is done synchronously, at startup. | ||||
// If the server isn't already running, startup continues, and the items in | // If the server isn't already running, startup continues, and the items in | ||||
// savedPaymentRequest will be handled when uiReady() is called. | // savedPaymentRequest will be handled when uiReady() is called. | ||||
// | // | ||||
bool PaymentServer::ipcSendCommandLine() { | bool PaymentServer::ipcSendCommandLine() { | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | |||||
void PaymentServer::handleURIOrFile(const QString &s) { | void PaymentServer::handleURIOrFile(const QString &s) { | ||||
if (saveURIs) { | if (saveURIs) { | ||||
savedPaymentRequests.append(s); | savedPaymentRequests.append(s); | ||||
return; | return; | ||||
} | } | ||||
// bitcoincash: URI | // bitcoincash: URI | ||||
QString scheme = GUIUtil::bitcoinURIScheme(Params(), false); | QString scheme = GUIUtil::bitcoinURIScheme(Params(), true); | ||||
if (s.startsWith(scheme + ":", Qt::CaseInsensitive)) { | if (s.startsWith(scheme + ":", Qt::CaseInsensitive)) { | ||||
#if QT_VERSION < 0x050000 | #if QT_VERSION < 0x050000 | ||||
QUrl uri(s); | QUrl uri(s); | ||||
#else | #else | ||||
QUrlQuery uri((QUrl(s))); | QUrlQuery uri((QUrl(s))); | ||||
#endif | #endif | ||||
if (uri.hasQueryItem("r")) { | if (uri.hasQueryItem("r")) { | ||||
// payment request URI | // payment request URI | ||||
▲ Show 20 Lines • Show All 418 Lines • Show Last 20 Lines |