19 #include <openssl/x509.h>
20 #include <openssl/x509_vfy.h>
21 #include <QApplication>
23 #include <QDataStream>
27 #include <QFileOpenEvent>
30 #include <QLocalServer>
31 #include <QLocalSocket>
32 #include <QNetworkAccessManager>
33 #include <QNetworkProxy>
34 #include <QNetworkReply>
35 #include <QNetworkRequest>
36 #include <QSslCertificate>
39 #include <QStringList>
40 #include <QTextDocument>
42 #if QT_VERSION < 0x050000
48 using namespace boost;
71 static QString ipcServerName()
73 QString name(
"AnoncoinQt");
78 QString ddir(QString::fromStdString(
GetDataDir(
true).
string()));
79 name.append(QString::number(qHash(ddir)));
89 static QList<QString> savedPaymentRequests;
91 static void ReportInvalidCertificate(
const QSslCertificate& cert)
93 qDebug() <<
"ReportInvalidCertificate : Payment server found an invalid certificate: " << cert.subjectInfo(QSslCertificate::CommonName);
118 QString certFile = QString::fromStdString(
GetArg(
"-rootcertificates",
"-system-"));
120 if (certFile.isEmpty())
123 QList<QSslCertificate> certList;
125 if (certFile !=
"-system-")
127 certList = QSslCertificate::fromPath(certFile);
129 QSslSocket::setDefaultCaCertificates(certList);
132 certList = QSslSocket::systemCaCertificates ();
135 const QDateTime currentTime = QDateTime::currentDateTime();
136 foreach (
const QSslCertificate& cert, certList)
138 if (currentTime < cert.effectiveDate() || currentTime > cert.expiryDate()) {
139 ReportInvalidCertificate(cert);
142 #if QT_VERSION >= 0x050000
143 if (cert.isBlacklisted()) {
144 ReportInvalidCertificate(cert);
148 QByteArray certData = cert.toDer();
149 const unsigned char *data = (
const unsigned char *)certData.data();
151 X509* x509 = d2i_X509(0, &data, certData.size());
160 ReportInvalidCertificate(cert);
164 qDebug() <<
"PaymentServer::LoadRootCAs : Loaded " << nRootCerts <<
" root certificates";
184 for (
int i = 1; i < argc; i++)
186 QString arg(argv[i]);
187 if (arg.startsWith(
"-"))
192 savedPaymentRequests.append(arg);
200 if (!address.IsValid())
206 else if (QFile::exists(arg))
208 savedPaymentRequests.append(arg);
211 if (readPaymentRequest(arg, request))
223 qDebug() <<
"PaymentServer::ipcSendCommandLine : Payment request file does not exist: " << arg;
237 bool fResult =
false;
238 foreach (
const QString& r, savedPaymentRequests)
240 QLocalSocket* socket =
new QLocalSocket();
241 socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
249 QDataStream out(&block, QIODevice::WriteOnly);
250 out.setVersion(QDataStream::Qt_4_0);
252 out.device()->seek(0);
253 socket->write(block);
257 socket->disconnectFromServer();
274 GOOGLE_PROTOBUF_VERIFY_VERSION;
280 parent->installEventFilter(
this);
282 QString name = ipcServerName();
285 QLocalServer::removeServer(name);
287 if (startLocalServer)
293 QMessageBox::critical(0, tr(
"Payment request error"),
294 tr(
"Cannot start anoncoin: click-to-pay handler"));
305 google::protobuf::ShutdownProtobufLibrary();
315 if (event->type() == QEvent::FileOpen)
317 QFileOpenEvent *fileEvent =
static_cast<QFileOpenEvent*
>(event);
318 if (!fileEvent->file().isEmpty())
320 else if (!fileEvent->url().isEmpty())
326 return QObject::eventFilter(
object, event);
345 qDebug() <<
"PaymentServer::initNetManager : Using SOCKS5 proxy" << proxy.hostName() <<
":" << proxy.port();
348 qDebug() <<
"PaymentServer::initNetManager : No active proxy server found.";
350 connect(
netManager, SIGNAL(finished(QNetworkReply*)),
352 connect(
netManager, SIGNAL(sslErrors(QNetworkReply*,
const QList<QSslError> &)),
353 this, SLOT(
reportSslErrors(QNetworkReply*,
const QList<QSslError> &)));
361 foreach (
const QString& s, savedPaymentRequests)
365 savedPaymentRequests.clear();
372 savedPaymentRequests.append(s);
378 #if QT_VERSION < 0x050000
381 QUrlQuery uri((QUrl(s)));
383 if (uri.hasQueryItem(
"r"))
386 temp.append(uri.queryItemValue(
"r"));
387 QString decoded = QUrl::fromPercentEncoding(temp);
388 QUrl fetchUrl(decoded, QUrl::StrictMode);
390 if (fetchUrl.isValid())
392 qDebug() <<
"PaymentServer::handleURIOrFile : fetchRequest(" << fetchUrl <<
")";
397 qDebug() <<
"PaymentServer::handleURIOrFile : Invalid URL: " << fetchUrl;
398 emit
message(tr(
"URI handling"),
399 tr(
"Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
411 emit
message(tr(
"URI handling"),
412 tr(
"URI cannot be parsed! This can be caused by an invalid Anoncoin address or malformed URI parameters."),
419 if (QFile::exists(s))
426 emit
message(tr(
"Payment request file handling"),
427 tr(
"Payment request file cannot be read! This can be caused by an invalid payment request file."),
436 QLocalSocket *clientConnection =
uriServer->nextPendingConnection();
438 while (clientConnection->bytesAvailable() < (int)
sizeof(quint32))
439 clientConnection->waitForReadyRead();
441 connect(clientConnection, SIGNAL(disconnected()),
442 clientConnection, SLOT(deleteLater()));
444 QDataStream in(clientConnection);
445 in.setVersion(QDataStream::Qt_4_0);
446 if (clientConnection->bytesAvailable() < (int)
sizeof(quint16)) {
458 if (!f.open(QIODevice::ReadOnly))
460 qDebug() <<
"PaymentServer::readPaymentRequest : Failed to open " << filename;
464 if (f.size() > MAX_PAYMENT_REQUEST_SIZE)
466 qDebug() <<
"PaymentServer::readPaymentRequest : " << filename <<
" too large";
470 QByteArray data = f.readAll();
472 return request.
parse(data);
485 QList<std::pair<CScript, qint64> > sendingTos = request.
getPayTo();
486 QStringList addresses;
493 addresses.append(QString::fromStdString(
CAnoncoinAddress(dest).ToString()));
499 emit
message(tr(
"Payment request error"),
500 tr(
"Unverified payment requests to custom payment scripts are unsupported."),
506 CTxOut txOut(sendingTo.second, sendingTo.first);
508 QString msg = tr(
"Requested payment amount of %1 is too small (considered dust).")
511 qDebug() <<
"PaymentServer::processPaymentRequest : " << msg;
516 recipient.
amount += sendingTo.second;
519 recipient.
address = addresses.join(
"<br />");
522 qDebug() <<
"PaymentServer::processPaymentRequest : Secure payment request from " << recipient.
authenticatedMerchant;
525 qDebug() <<
"PaymentServer::processPaymentRequest : Insecure payment request to " << addresses.join(
", ");
533 QNetworkRequest netRequest;
534 netRequest.setAttribute(QNetworkRequest::User,
"PaymentRequest");
535 netRequest.setUrl(url);
536 netRequest.setRawHeader(
"User-Agent",
CLIENT_NAME.c_str());
547 QNetworkRequest netRequest;
548 netRequest.setAttribute(QNetworkRequest::User,
"PaymentACK");
549 netRequest.setUrl(QString::fromStdString(details.
payment_url()));
551 netRequest.setRawHeader(
"User-Agent",
CLIENT_NAME.c_str());
560 std::string strAccount = account.toStdString();
562 if (!refundAddresses.empty()) {
581 qDebug() <<
"PaymentServer::fetchPaymentACK : Error getting refund key, refund_to not set";
586 netRequest.setHeader(QNetworkRequest::ContentLengthHeader, length);
587 QByteArray serData(length,
'\0');
588 if (payment.SerializeToArray(serData.data(), length)) {
593 qDebug() <<
"PaymentServer::fetchPaymentACK : Error serializing payment message";
599 reply->deleteLater();
600 if (reply->error() != QNetworkReply::NoError)
602 QString msg = tr(
"Error communicating with %1: %2")
603 .arg(reply->request().url().toString())
604 .arg(reply->errorString());
606 qDebug() <<
"PaymentServer::netRequestFinished : " << msg;
611 QByteArray data = reply->readAll();
613 QString requestType = reply->request().attribute(QNetworkRequest::User).toString();
614 if (requestType ==
"PaymentRequest")
624 qDebug() <<
"PaymentServer::netRequestFinished : Error processing payment request";
625 emit
message(tr(
"Payment request error"),
626 tr(
"Payment request cannot be parsed!"),
632 else if (requestType ==
"PaymentACK")
635 if (!paymentACK.ParseFromArray(data.data(), data.size()))
637 QString msg = tr(
"Bad response from server %1")
638 .arg(reply->request().url().toString());
640 qDebug() <<
"PaymentServer::netRequestFinished : " << msg;
655 foreach (
const QSslError& err, errs) {
656 qDebug() <<
"PaymentServer::reportSslErrors : " << err;
657 errString += err.errorString() +
"\n";
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
bool IsDust(int64_t nMinRelayTxFee) const
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
PaymentRequestPlus paymentRequest
void message(const QString &title, const QString &message, unsigned int style)
const char * ANONCOIN_PAYMENTACK_CONTENTTYPE
static bool readPaymentRequest(const QString &filename, PaymentRequestPlus &request)
void set_script(const ::std::string &value)
void setOptionsModel(OptionsModel *optionsModel)
const char * ANONCOIN_REQUEST_MIMETYPE
CCriticalSection cs_wallet
Main wallet lock.
static QString formatWithUnit(int unit, qint64 amount, bool plussign=false)
Format as string (with unit)
bool eventFilter(QObject *object, QEvent *event)
void handlePaymentACK(const QString &paymentACKMsg)
bool getMerchant(X509_STORE *certStore, QString &merchant) const
void receivedPaymentACK(const QString &paymentACKMsg)
bool has_payment_url() const
bool parseAnoncoinURI(const QUrl &uri, SendCoinsRecipient *out)
void set_merchant_data(const ::std::string &value)
void receivedPaymentRequest(SendCoinsRecipient)
QString HtmlEscape(const QString &str, bool fMultiLine)
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 bool ipcSendCommandLine()
void netRequestFinished(QNetworkReply *)
const ::std::string & memo() const
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.
base58-encoded Anoncoin addresses.
const int ANONCOIN_IPC_CONNECT_TIMEOUT
const ::std::string & network() const
const payments::PaymentDetails & getDetails() const
An output of a transaction.
PaymentServer(QObject *parent, bool startLocalServer=true)
const QString ANONCOIN_IPC_PREFIX("anoncoin:")
QNetworkAccessManager * netManager
const std::string CLIENT_NAME
std::set< CTxDestination > GetAccountAddresses(std::string strAccount) const
bool parse(const QByteArray &data)
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
void reportSslErrors(QNetworkReply *, const QList< QSslError > &)
void fetchPaymentACK(CWallet *wallet, SendCoinsRecipient recipient, QByteArray transaction)
Interface from Qt to configuration data structure for Anoncoin client.
Serialized script, used inside transaction inputs and outputs.
const char * ANONCOIN_PAYMENTACK_MIMETYPE
A reference to a CKey: the Hash160 of its serialized public key.
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
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)
static void LoadRootCAs(X509_STORE *store=NULL)
const ::std::string & merchant_data() const
QString authenticatedMerchant
QList< std::pair< CScript, qint64 > > getPayTo() const