18 #include <openssl/x509.h>
19 #include <openssl/x509_vfy.h>
20 #include <QApplication>
22 #include <QDataStream>
26 #include <QFileOpenEvent>
29 #include <QLocalServer>
30 #include <QLocalSocket>
31 #include <QNetworkAccessManager>
32 #include <QNetworkProxy>
33 #include <QNetworkReply>
34 #include <QNetworkRequest>
35 #include <QSslCertificate>
38 #include <QStringList>
39 #include <QTextDocument>
41 #if QT_VERSION < 0x050000
47 using namespace boost;
72 QString name(
"BitcoinQt");
77 QString ddir(QString::fromStdString(
GetDataDir(
true).
string()));
78 name.append(QString::number(qHash(ddir)));
92 qDebug() <<
"ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName);
117 QString certFile = QString::fromStdString(
GetArg(
"-rootcertificates",
"-system-"));
119 if (certFile.isEmpty())
122 QList<QSslCertificate> certList;
124 if (certFile !=
"-system-")
126 certList = QSslCertificate::fromPath(certFile);
128 QSslSocket::setDefaultCaCertificates(certList);
131 certList = QSslSocket::systemCaCertificates ();
134 const QDateTime currentTime = QDateTime::currentDateTime();
135 foreach (
const QSslCertificate& cert, certList)
137 if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
141 #if QT_VERSION >= 0x050000
142 if (cert.isBlacklisted()) {
147 QByteArray certData = cert.toDer();
148 const unsigned char *
data = (
const unsigned char *)certData.data();
150 X509* x509 = d2i_X509(0, &data, certData.size());
163 qDebug() <<
"PaymentServer::LoadRootCAs : Loaded " << nRootCerts <<
" root certificates";
183 for (
int i = 1; i < argc; i++)
185 QString arg(argv[i]);
186 if (arg.startsWith(
"-"))
199 if (!address.IsValid())
205 else if (QFile::exists(arg))
210 if (readPaymentRequest(arg, request))
222 qDebug() <<
"PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
236 bool fResult =
false;
239 QLocalSocket* socket =
new QLocalSocket();
240 socket->connectToServer(
ipcServerName(), QIODevice::WriteOnly);
241 if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
248 QDataStream out(&block, QIODevice::WriteOnly);
249 out.setVersion(QDataStream::Qt_4_0);
251 out.device()->seek(0);
252 socket->write(block);
255 socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);
256 socket->disconnectFromServer();
273 GOOGLE_PROTOBUF_VERIFY_VERSION;
279 parent->installEventFilter(
this);
284 QLocalServer::removeServer(name);
286 if (startLocalServer)
292 QMessageBox::critical(0, tr(
"Payment request error"),
293 tr(
"Cannot start bitcoin: click-to-pay handler"));
304 google::protobuf::ShutdownProtobufLibrary();
314 if (event->type() == QEvent::FileOpen)
316 QFileOpenEvent *fileEvent =
static_cast<QFileOpenEvent*
>(event);
317 if (!fileEvent->file().isEmpty())
319 else if (!fileEvent->url().isEmpty())
325 return QObject::eventFilter(
object, event);
342 if (proxy.type() == QNetworkProxy::Socks5Proxy) {
345 qDebug() <<
"PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() <<
":" << proxy.port();
348 qDebug() <<
"PaymentServer::initNetManager : No active proxy server found.";
351 emit
message(tr(
"Net manager warning"),
352 tr(
"Your active proxy doesn't support SOCKS5, which is required for payment requests via proxy."),
355 connect(
netManager, SIGNAL(finished(QNetworkReply*)),
357 connect(
netManager, SIGNAL(sslErrors(QNetworkReply*,
const QList<QSslError> &)),
358 this, SLOT(
reportSslErrors(QNetworkReply*,
const QList<QSslError> &)));
383 #if QT_VERSION < 0x050000
386 QUrlQuery uri((QUrl(s)));
388 if (uri.hasQueryItem(
"r"))
391 temp.append(uri.queryItemValue(
"r"));
392 QString decoded = QUrl::fromPercentEncoding(temp);
393 QUrl fetchUrl(decoded, QUrl::StrictMode);
395 if (fetchUrl.isValid())
397 qDebug() <<
"PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl <<
")";
402 qDebug() <<
"PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl;
403 emit
message(tr(
"URI handling"),
404 tr(
"Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
416 emit
message(tr(
"URI handling"),
417 tr(
"URI can not be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
424 if (QFile::exists(s))
431 emit
message(tr(
"Payment request file handling"),
432 tr(
"Payment request file can not be read or processed! This can be caused by an invalid payment request file."),
441 QLocalSocket *clientConnection =
uriServer->nextPendingConnection();
443 while (clientConnection->bytesAvailable() < (
int)
sizeof(quint32))
444 clientConnection->waitForReadyRead();
446 connect(clientConnection, SIGNAL(disconnected()),
447 clientConnection, SLOT(deleteLater()));
449 QDataStream in(clientConnection);
450 in.setVersion(QDataStream::Qt_4_0);
451 if (clientConnection->bytesAvailable() < (
int)
sizeof(quint16)) {
463 if (!f.open(QIODevice::ReadOnly))
465 qDebug() <<
"PaymentServer::readPaymentRequest : Failed to open " << filename;
471 qDebug() <<
"PaymentServer::readPaymentRequest : " << filename <<
" too large";
475 QByteArray
data = f.readAll();
477 return request.
parse(data);
490 QList<std::pair<CScript, qint64> > sendingTos = request.
getPayTo();
491 QStringList addresses;
498 addresses.append(QString::fromStdString(
CBitcoinAddress(dest).ToString()));
504 emit
message(tr(
"Payment request error"),
505 tr(
"Unverified payment requests to custom payment scripts are unsupported."),
511 CTxOut txOut(sendingTo.second, sendingTo.first);
513 QString msg = tr(
"Requested payment amount of %1 is too small (considered dust).")
516 qDebug() <<
"PaymentServer::processPaymentRequest : " << msg;
521 recipient.
amount += sendingTo.second;
524 recipient.
address = addresses.join(
"<br />");
527 qDebug() <<
"PaymentServer::processPaymentRequest : Secure payment request from " << recipient.
authenticatedMerchant;
530 qDebug() <<
"PaymentServer::processPaymentRequest : Insecure payment request to " << addresses.join(
", ");
538 QNetworkRequest netRequest;
539 netRequest.setAttribute(QNetworkRequest::User,
"PaymentRequest");
540 netRequest.setUrl(url);
541 netRequest.setRawHeader(
"User-Agent",
CLIENT_NAME.c_str());
552 QNetworkRequest netRequest;
553 netRequest.setAttribute(QNetworkRequest::User,
"PaymentACK");
554 netRequest.setUrl(QString::fromStdString(details.
payment_url()));
556 netRequest.setRawHeader(
"User-Agent",
CLIENT_NAME.c_str());
565 std::string strAccount = account.toStdString();
567 if (!refundAddresses.empty()) {
586 qDebug() <<
"PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set";
591 netRequest.setHeader(QNetworkRequest::ContentLengthHeader, length);
592 QByteArray serData(length,
'\0');
593 if (payment.SerializeToArray(serData.data(), length)) {
598 qDebug() <<
"PaymentServer::fetchPaymentACK : Error serializing payment message";
604 reply->deleteLater();
605 if (reply->error() != QNetworkReply::NoError)
607 QString msg = tr(
"Error communicating with %1: %2")
608 .arg(reply->request().url().toString())
609 .arg(reply->errorString());
611 qDebug() <<
"PaymentServer::netRequestFinished : " << msg;
616 QByteArray
data = reply->readAll();
618 QString requestType = reply->request().attribute(QNetworkRequest::User).toString();
619 if (requestType ==
"PaymentRequest")
629 qDebug() <<
"PaymentServer::netRequestFinished : Error processing payment request";
630 emit
message(tr(
"Payment request error"),
631 tr(
"Payment request can not be parsed or processed!"),
637 else if (requestType ==
"PaymentACK")
640 if (!paymentACK.ParseFromArray(data.data(), data.size()))
642 QString msg = tr(
"Bad response from server %1")
643 .arg(reply->request().url().toString());
645 qDebug() <<
"PaymentServer::netRequestFinished : " << msg;
660 foreach (
const QSslError& err, errs) {
661 qDebug() <<
"PaymentServer::reportSslErrors : " << err;
662 errString += err.errorString() +
"\n";
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
const char * BITCOIN_PAYMENTACK_MIMETYPE
bool IsDust(int64_t nMinRelayTxFee) const
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
const char * BITCOIN_REQUEST_MIMETYPE
PaymentRequestPlus paymentRequest
void message(const QString &title, const QString &message, unsigned int style)
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false)
Format as string (with unit)
static bool readPaymentRequest(const QString &filename, PaymentRequestPlus &request)
static const int MAX_PAYMENT_REQUEST_SIZE
void set_script(const ::std::string &value)
void setOptionsModel(OptionsModel *optionsModel)
CCriticalSection cs_wallet
Main wallet lock.
bool eventFilter(QObject *object, QEvent *event)
void handlePaymentACK(const QString &paymentACKMsg)
bool getMerchant(X509_STORE *certStore, QString &merchant) const
void receivedPaymentACK(const QString &paymentACKMsg)
const std::string CLIENT_NAME
bool has_payment_url() const
void set_merchant_data(const ::std::string &value)
void receivedPaymentRequest(SendCoinsRecipient)
QString HtmlEscape(const QString &str, bool fMultiLine)
base58-encoded Bitcoin addresses.
const char * BITCOIN_PAYMENTACK_CONTENTTYPE
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
inline::std::string * add_transactions()
static X509_STORE * certStore
void handleURIOrFile(const QString &s)
static bool ipcParseCommandLine(int argc, char *argv[])
static void freeCertStore()
Force blocking, modal message box dialog (not just OS notification)
const ::std::string & payment_url() const
void SetDestination(const CTxDestination &address)
static void ReportInvalidCertificate(const QSslCertificate &cert)
static bool ipcSendCommandLine()
void netRequestFinished(QNetworkReply *)
const ::std::string & memo() const
const int BITCOIN_IPC_CONNECT_TIMEOUT
void SelectParams(CChainParams::Network network)
Sets the params returned by Params() to those for the given network.
void fetchRequest(const QUrl &url)
bool getProxySettings(QNetworkProxy &proxy) const
An encapsulated public key.
const ::std::string & network() const
const payments::PaymentDetails & getDetails() const
An output of a transaction.
PaymentServer(QObject *parent, bool startLocalServer=true)
QNetworkAccessManager * netManager
std::set< CTxDestination > GetAccountAddresses(std::string strAccount) const
static QList< QString > savedPaymentRequests
bool parse(const QByteArray &data)
void reportSslErrors(QNetworkReply *, const QList< QSslError > &)
void fetchPaymentACK(CWallet *wallet, SendCoinsRecipient recipient, QByteArray transaction)
Interface from Qt to configuration data structure for Bitcoin client.
Serialized script, used inside transaction inputs and outputs.
const QString BITCOIN_IPC_PREFIX("bitcoin:")
A reference to a CKey: the Hash160 of its serialized public key.
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
static QString ipcServerName()
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
void handleURIConnection()
static int64_t nMinRelayTxFee
Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) ...
inline::payments::Output * add_refund_to()
bool processPaymentRequest(PaymentRequestPlus &request, SendCoinsRecipient &recipient)
const ::std::string & memo() const
OptionsModel * optionsModel
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
bool GetKeyFromPool(CPubKey &key)
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
static const CCheckpointData data
static void LoadRootCAs(X509_STORE *store=NULL)
const ::std::string & merchant_data() const
QString authenticatedMerchant
QList< std::pair< CScript, qint64 > > getPayTo() const