allow unauthenticated redemptions of signed transactions from octree server

This commit is contained in:
Stephen Birarda 2014-07-31 10:05:26 -07:00
parent ce4336894a
commit eadae8ed1a
5 changed files with 154 additions and 68 deletions

View file

@ -9,11 +9,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
#include <QUuid>
#include <time.h>
#include <AccountManager.h>
#include <HTTPConnection.h>
#include <Logging.h>
#include <UUID.h>
@ -244,6 +247,10 @@ OctreeServer::OctreeServer(const QByteArray& packet) :
_averageLoopTime.updateAverage(0);
qDebug() << "Octree server starting... [" << this << "]";
// make sure the AccountManager has an Auth URL for payment redemptions
AccountManager::getInstance().setAuthURL(DEFAULT_NODE_AUTH_URL);
}
OctreeServer::~OctreeServer() {
@ -857,6 +864,8 @@ void OctreeServer::readPendingDatagrams() {
}
} else if (packetType == PacketTypeJurisdictionRequest) {
_jurisdictionSender->queueReceivedPacket(matchingNode, receivedPacket);
} else if (packetType == PacketTypeSignedTransactionPayment) {
handleSignedTransactionPayment(packetType, receivedPacket);
} else if (_octreeInboundPacketProcessor && getOctree()->handlesEditPacketType(packetType)) {
_octreeInboundPacketProcessor->queueReceivedPacket(matchingNode, receivedPacket);
} else {
@ -1204,6 +1213,49 @@ QString OctreeServer::getStatusLink() {
return result;
}
void OctreeServer::handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram) {
// for now we're not verifying that this is actual payment for any octree edits
// just use the AccountManager to send it up to the data server and have it redeemed
AccountManager& accountManager = AccountManager::getInstance();
const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE = 72;
const int NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE = 256;
int numBytesPacketHeader = numBytesForPacketHeaderGivenPacketType(packetType);
// pull out the transaction message in binary
QByteArray messageHex = datagram.mid(numBytesPacketHeader, NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE).toHex();
// pull out the binary signed message digest
QByteArray signatureHex = datagram.mid(numBytesPacketHeader + NUM_BYTES_SIGNED_TRANSACTION_BINARY_MESSAGE,
NUM_BYTES_SIGNED_TRANSACTION_BINARY_SIGNATURE).toHex();
// setup the QJSONObject we are posting
QJsonObject postObject;
const QString TRANSACTION_OBJECT_MESSAGE_KEY = "message";
const QString TRANSACTION_OBJECT_SIGNATURE_KEY = "signature";
const QString POST_OBJECT_TRANSACTION_KEY = "transaction";
QJsonObject transactionObject;
transactionObject.insert(TRANSACTION_OBJECT_MESSAGE_KEY, QString(messageHex));
transactionObject.insert(TRANSACTION_OBJECT_SIGNATURE_KEY, QString(signatureHex));
postObject.insert(POST_OBJECT_TRANSACTION_KEY, transactionObject);
// setup our callback params
JSONCallbackParameters callbackParameters;
callbackParameters.jsonCallbackReceiver = this;
callbackParameters.jsonCallbackMethod = "handleSignedTransactionPaymentResponse";
accountManager.unauthenticatedRequest("/api/v1/transactions/redeem", QNetworkAccessManager::PostOperation,
callbackParameters, QJsonDocument(postObject).toJson());
}
void OctreeServer::handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject) {
qDebug() << "STP response:" << jsonObject;
}
void OctreeServer::sendStatsPacket() {
// TODO: we have too many stats to fit in a single MTU... so for now, we break it into multiple JSON objects and
// send them separately. What we really should do is change the NodeList::sendStatsToDomainServer() to handle the

View file

@ -137,6 +137,9 @@ protected:
QString getConfiguration();
QString getStatusLink();
void handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram);
void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject);
int _argc;
const char** _argv;
char** _parsedArgV;

View file

@ -14,8 +14,6 @@
#include <WalletTransaction.h>
const int NUM_BYTES_SIGNED_TRANSACTION_MESSAGE = 72;
class SignedWalletTransaction : public WalletTransaction {
Q_OBJECT
public:

View file

@ -15,15 +15,15 @@
#include <QtCore/QMap>
#include <QtCore/QStringList>
#include <QtCore/QUrlQuery>
#include <QtNetwork/QHttpMultiPart>
#include <QtNetwork/QNetworkRequest>
#include <QHttpMultiPart>
#include "NodeList.h"
#include "PacketHeaders.h"
#include "AccountManager.h"
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = false;
const bool VERBOSE_HTTP_REQUEST_DEBUGGING = true;
AccountManager& AccountManager::getInstance() {
static AccountManager sharedInstance;
@ -62,6 +62,8 @@ AccountManager::AccountManager() :
qRegisterMetaType<QNetworkAccessManager::Operation>("QNetworkAccessManager::Operation");
qRegisterMetaType<JSONCallbackParameters>("JSONCallbackParameters");
qRegisterMetaType<QHttpMultiPart*>("QHttpMultiPart*");
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
}
@ -142,90 +144,113 @@ void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessMan
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart) {
QMetaObject::invokeMethod(this, "invokedRequest",
Q_ARG(const QString&, path),
Q_ARG(bool, true),
Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray),
Q_ARG(QHttpMultiPart*, dataMultiPart));
}
void AccountManager::invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart) {
QMetaObject::invokeMethod(this, "invokedRequest",
Q_ARG(const QString&, path),
Q_ARG(bool, false),
Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray),
Q_ARG(QHttpMultiPart*, dataMultiPart));
}
void AccountManager::invokedRequest(const QString& path,
bool requiresAuthentication,
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart) {
NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
if (hasValidAccessToken()) {
QNetworkRequest authenticatedRequest;
QUrl requestURL = _authURL;
if (path.startsWith("/")) {
requestURL.setPath(path);
QNetworkRequest networkRequest;
QUrl requestURL = _authURL;
if (path.startsWith("/")) {
requestURL.setPath(path);
} else {
requestURL.setPath("/" + path);
}
if (requiresAuthentication) {
if (hasValidAccessToken()) {
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
} else {
requestURL.setPath("/" + path);
qDebug() << "No valid access token present. Bailing on authenticated invoked request.";
return;
}
requestURL.setQuery("access_token=" + _accountInfo.getAccessToken().token);
authenticatedRequest.setUrl(requestURL);
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString());
if (!dataByteArray.isEmpty()) {
qDebug() << "The POST/PUT body -" << QString(dataByteArray);
}
}
networkRequest.setUrl(requestURL);
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "Making an authenticated request to" << qPrintable(requestURL.toString());
if (!dataByteArray.isEmpty()) {
qDebug() << "The POST/PUT body -" << QString(dataByteArray);
}
QNetworkReply* networkReply = NULL;
switch (operation) {
case QNetworkAccessManager::GetOperation:
networkReply = networkAccessManager.get(authenticatedRequest);
break;
case QNetworkAccessManager::PostOperation:
case QNetworkAccessManager::PutOperation:
if (dataMultiPart) {
if (operation == QNetworkAccessManager::PostOperation) {
networkReply = networkAccessManager.post(authenticatedRequest, dataMultiPart);
} else {
networkReply = networkAccessManager.put(authenticatedRequest, dataMultiPart);
}
dataMultiPart->setParent(networkReply);
}
QNetworkReply* networkReply = NULL;
switch (operation) {
case QNetworkAccessManager::GetOperation:
networkReply = networkAccessManager.get(networkRequest);
break;
case QNetworkAccessManager::PostOperation:
case QNetworkAccessManager::PutOperation:
if (dataMultiPart) {
if (operation == QNetworkAccessManager::PostOperation) {
networkReply = networkAccessManager.post(networkRequest, dataMultiPart);
} else {
authenticatedRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
if (operation == QNetworkAccessManager::PostOperation) {
networkReply = networkAccessManager.post(authenticatedRequest, dataByteArray);
} else {
networkReply = networkAccessManager.put(authenticatedRequest, dataByteArray);
}
networkReply = networkAccessManager.put(networkRequest, dataMultiPart);
}
break;
case QNetworkAccessManager::DeleteOperation:
networkReply = networkAccessManager.sendCustomRequest(authenticatedRequest, "DELETE");
break;
default:
// other methods not yet handled
break;
}
if (networkReply) {
if (!callbackParams.isEmpty()) {
// if we have information for a callback, insert the callbackParams into our local map
_pendingCallbackMap.insert(networkReply, callbackParams);
if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) {
callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)),
callbackParams.updateSlot.toStdString().c_str());
dataMultiPart->setParent(networkReply);
} else {
networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
if (operation == QNetworkAccessManager::PostOperation) {
networkReply = networkAccessManager.post(networkRequest, dataByteArray);
} else {
networkReply = networkAccessManager.put(networkRequest, dataByteArray);
}
}
// if we ended up firing of a request, hook up to it now
connect(networkReply, SIGNAL(finished()), SLOT(processReply()));
break;
case QNetworkAccessManager::DeleteOperation:
networkReply = networkAccessManager.sendCustomRequest(networkRequest, "DELETE");
break;
default:
// other methods not yet handled
break;
}
if (networkReply) {
if (!callbackParams.isEmpty()) {
// if we have information for a callback, insert the callbackParams into our local map
_pendingCallbackMap.insert(networkReply, callbackParams);
if (callbackParams.updateReciever && !callbackParams.updateSlot.isEmpty()) {
callbackParams.updateReciever->connect(networkReply, SIGNAL(uploadProgress(qint64, qint64)),
callbackParams.updateSlot.toStdString().c_str());
}
}
// if we ended up firing of a request, hook up to it now
connect(networkReply, SIGNAL(finished()), SLOT(processReply()));
}
}

View file

@ -47,6 +47,12 @@ public:
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(),
QHttpMultiPart* dataMultiPart = NULL);
void unauthenticatedRequest(const QString& path,
QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation,
const JSONCallbackParameters& callbackParams = JSONCallbackParameters(),
const QByteArray& dataByteArray = QByteArray(),
QHttpMultiPart* dataMultiPart = NULL);
const QUrl& getAuthURL() const { return _authURL; }
void setAuthURL(const QUrl& authURL);
@ -88,7 +94,9 @@ private:
void passSuccessToCallback(QNetworkReply* reply);
void passErrorToCallback(QNetworkReply* reply);
Q_INVOKABLE void invokedRequest(const QString& path, QNetworkAccessManager::Operation operation,
Q_INVOKABLE void invokedRequest(const QString& path,
bool requiresAuthentication,
QNetworkAccessManager::Operation operation,
const JSONCallbackParameters& callbackParams,
const QByteArray& dataByteArray,
QHttpMultiPart* dataMultiPart);