mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:44:11 +02:00
allow unauthenticated redemptions of signed transactions from octree server
This commit is contained in:
parent
ce4336894a
commit
eadae8ed1a
5 changed files with 154 additions and 68 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include <WalletTransaction.h>
|
||||
|
||||
const int NUM_BYTES_SIGNED_TRANSACTION_MESSAGE = 72;
|
||||
|
||||
class SignedWalletTransaction : public WalletTransaction {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue