diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp
index 42af8ff1b9..d0a17287cb 100644
--- a/assignment-client/src/octree/OctreeServer.cpp
+++ b/assignment-client/src/octree/OctreeServer.cpp
@@ -861,8 +861,6 @@ void OctreeServer::readPendingDatagram(const QByteArray& receivedPacket, const H
}
} 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 {
@@ -1245,51 +1243,6 @@ 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) {
- // pull the ID to debug the transaction
- QString transactionIDString = jsonObject["data"].toObject()["transaction"].toObject()["id"].toString();
- qDebug() << "Redeemed transaction with ID" << transactionIDString << "successfully.";
-}
-
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
diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h
index aa0c419dd4..2fcaae8c78 100644
--- a/assignment-client/src/octree/OctreeServer.h
+++ b/assignment-client/src/octree/OctreeServer.h
@@ -127,8 +127,6 @@ public slots:
void nodeKilled(SharedNodePointer node);
void sendStatsPacket();
- void handleSignedTransactionPaymentResponse(const QJsonObject& jsonObject);
-
void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle
void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
@@ -141,7 +139,6 @@ protected:
QString getConfiguration();
QString getStatusLink();
- void handleSignedTransactionPayment(PacketType packetType, const QByteArray& datagram);
void setupDatagramProcessingThread();
int _argc;
diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt
index 17d8b61b11..9090a1b637 100644
--- a/domain-server/CMakeLists.txt
+++ b/domain-server/CMakeLists.txt
@@ -38,4 +38,18 @@ endif ()
# link the shared hifi libraries
link_hifi_libraries(embedded-webserver networking shared)
+# find OpenSSL
+find_package(OpenSSL REQUIRED)
+
+if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
+ # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto
+ message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings."
+ "\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.")
+endif ()
+
+include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+
+# append OpenSSL to our list of libraries to link
+list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}")
+
link_shared_dependencies()
\ No newline at end of file
diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json
index 38df52c8eb..3a1fbd4526 100644
--- a/domain-server/resources/describe-settings.json
+++ b/domain-server/resources/describe-settings.json
@@ -59,6 +59,20 @@
"type": "password",
"help": "Password used for basic HTTP authentication. Leave this blank if you do not want to change it.",
"value-hidden": true
+ },
+ {
+ "name": "allowed_users",
+ "type": "table",
+ "label": "Allowed Users",
+ "help": "List the High Fidelity names for people you want to be able to connect to this domain. An empty list means everyone. You can always connect from this machine.",
+ "numbered": false,
+ "columns": [
+ {
+ "name": "username",
+ "label": "Username",
+ "can_set": true
+ }
+ ]
}
]
},
diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js
index 2b8b42d029..3b7e449d4c 100644
--- a/domain-server/resources/web/js/settings.js
+++ b/domain-server/resources/web/js/settings.js
@@ -259,7 +259,7 @@ function makeTable(setting, setting_name, setting_value) {
html += "
" + col.label + "
" // Data
})
- html += "
+/-
"
+ html += "
"
// populate rows in the table from existing values
var row_num = 1
@@ -279,13 +279,13 @@ function makeTable(setting, setting_name, setting_value) {
html += "
"
if (isArray) {
- colIsArray = _.isArray(row)
- colValue = colIsArray ? row : row[col.name]
+ rowIsObject = setting.columns.length > 1
+ colValue = rowIsObject ? row[col.name] : row
html += colValue
// for arrays we add a hidden input to this td so that values can be posted appropriately
html += ""
+ + (rowIsObject ? "." + col.name : "") + "' value='" + colValue + "'/>"
} else if (row.hasOwnProperty(col.name)) {
html += row[col.name]
}
diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp
index fa7a0fe012..bbfa01c709 100644
--- a/domain-server/src/DomainServer.cpp
+++ b/domain-server/src/DomainServer.cpp
@@ -9,6 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include
+#include
+
#include
#include
#include
@@ -44,8 +47,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
_oauthProviderURL(),
_oauthClientID(),
_hostname(),
- _networkReplyUUIDMap(),
- _sessionAuthenticationHash(),
_webAuthenticationStateSet(),
_cookieSessionHash(),
_settingsManager()
@@ -80,6 +81,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
// setup automatic networking settings with data server
setupAutomaticNetworking();
+
+ // preload some user public keys so they can connect on first request
+ preloadAllowedUserPublicKeys();
}
}
@@ -507,8 +511,6 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSetwriteUnverifiedDatagram(oauthRequestByteArray, senderSockAddr);
-
- return;
- }
+ QList nodeInterestList;
+ QString username;
+ QByteArray usernameSignature;
+
+ packetStream >> nodeInterestList >> username >> usernameSignature;
+
+ if (!isAssignment && !shouldAllowConnectionFromNode(username, usernameSignature, senderSockAddr)) {
+ // this is an agent and we've decided we won't let them connect - send them a packet to deny connection
+ QByteArray usernameRequestByteArray = byteArrayWithPopulatedHeader(PacketTypeDomainConnectionDenied);
+
+ // send this oauth request datagram back to the client
+ LimitedNodeList::getInstance()->writeUnverifiedDatagram(usernameRequestByteArray, senderSockAddr);
+
+ return;
}
if ((!isAssignment && !STATICALLY_ASSIGNED_NODES.contains(nodeType))
@@ -610,15 +602,109 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock
}
// if we have a username from an OAuth connect request, set it on the DomainServerNodeData
- nodeData->setUsername(connectedUsername);
-
+ nodeData->setUsername(username);
nodeData->setSendingSockAddr(senderSockAddr);
// reply back to the user with a PacketTypeDomainList
- sendDomainListToNode(newNode, senderSockAddr, nodeInterestListFromPacket(packet, numPreInterestBytes));
+ sendDomainListToNode(newNode, senderSockAddr, nodeInterestList.toSet());
}
}
+const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users";
+
+bool DomainServer::shouldAllowConnectionFromNode(const QString& username,
+ const QByteArray& usernameSignature,
+ const HifiSockAddr& senderSockAddr) {
+ static const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(),
+ ALLOWED_USERS_SETTINGS_KEYPATH);
+ static QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
+
+ if (allowedUsers.count() > 0) {
+ // this is an agent, we need to ask them to provide us with their signed username to see if they are allowed in
+ // we always let in a user who is sending a packet from our local socket or from the localhost address
+
+ if (senderSockAddr.getAddress() != LimitedNodeList::getInstance()->getLocalSockAddr().getAddress()
+ && senderSockAddr.getAddress() != QHostAddress::LocalHost) {
+ if (allowedUsers.contains(username)) {
+ // it's possible this user can be allowed to connect, but we need to check their username signature
+
+ QByteArray publicKeyArray = _userPublicKeys.value(username);
+ if (!publicKeyArray.isEmpty()) {
+ // if we do have a public key for the user, check for a signature match
+
+ const unsigned char* publicKeyData = reinterpret_cast(publicKeyArray.constData());
+
+ // first load up the public key into an RSA struct
+ RSA* rsaPublicKey = d2i_RSAPublicKey(NULL, &publicKeyData, publicKeyArray.size());
+
+ if (rsaPublicKey) {
+ QByteArray decryptedArray(RSA_size(rsaPublicKey), 0);
+ int decryptResult = RSA_public_decrypt(usernameSignature.size(),
+ reinterpret_cast(usernameSignature.constData()),
+ reinterpret_cast(decryptedArray.data()),
+ rsaPublicKey, RSA_PKCS1_PADDING);
+
+ if (decryptResult != -1) {
+ if (username == decryptedArray) {
+ qDebug() << "Username signature matches for" << username << "- allowing connection.";
+
+ // free up the public key before we return
+ RSA_free(rsaPublicKey);
+
+ return true;
+ } else {
+ qDebug() << "Username signature did not match for" << username << "- denying connection.";
+ }
+ } else {
+ qDebug() << "Couldn't decrypt user signature for" << username << "- denying connection.";
+ }
+
+ // free up the public key, we don't need it anymore
+ RSA_free(rsaPublicKey);
+ } else {
+ // we can't let this user in since we couldn't convert their public key to an RSA key we could use
+ qDebug() << "Couldn't convert data to RSA key for" << username << "- denying connection.";
+ }
+ }
+
+ requestUserPublicKey(username);
+ }
+ }
+ } else {
+ // since we have no allowed user list, let them all in
+ return true;
+ }
+
+ return false;
+}
+
+void DomainServer::preloadAllowedUserPublicKeys() {
+ const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_USERS_SETTINGS_KEYPATH);
+ QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList();
+
+ if (allowedUsers.size() > 0) {
+ // in the future we may need to limit how many requests here - for now assume that lists of allowed users are not
+ // going to create > 100 requests
+ foreach(const QString& username, allowedUsers) {
+ requestUserPublicKey(username);
+ }
+ }
+}
+
+void DomainServer::requestUserPublicKey(const QString& username) {
+ // even if we have a public key for them right now, request a new one in case it has just changed
+ JSONCallbackParameters callbackParams;
+ callbackParams.jsonCallbackReceiver = this;
+ callbackParams.jsonCallbackMethod = "publicKeyJSONCallback";
+
+ const QString USER_PUBLIC_KEY_PATH = "api/v1/users/%1/public_key";
+
+ qDebug() << "Requesting public key for user" << username;
+
+ AccountManager::getInstance().unauthenticatedRequest(USER_PUBLIC_KEY_PATH.arg(username),
+ QNetworkAccessManager::GetOperation, callbackParams);
+}
+
QUrl DomainServer::oauthRedirectURL() {
return QString("https://%1:%2/oauth").arg(_hostname).arg(_httpsManager->serverPort());
}
@@ -653,12 +739,9 @@ QUrl DomainServer::oauthAuthorizationURL(const QUuid& stateUUID) {
return authorizationURL;
}
-int DomainServer::parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,
- HifiSockAddr& localSockAddr, const QByteArray& packet,
- const HifiSockAddr& senderSockAddr) {
- QDataStream packetStream(packet);
- packetStream.skipRawData(numBytesForPacketHeader(packet));
-
+int DomainServer::parseNodeDataFromByteArray(QDataStream& packetStream, NodeType_t& nodeType,
+ HifiSockAddr& publicSockAddr, HifiSockAddr& localSockAddr,
+ const HifiSockAddr& senderSockAddr) {
packetStream >> nodeType;
packetStream >> publicSockAddr >> localSockAddr;
@@ -925,7 +1008,30 @@ void DomainServer::sendPendingTransactionsToServer() {
++i;
}
}
+}
+void DomainServer::publicKeyJSONCallback(QNetworkReply& requestReply) {
+ QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
+
+ if (jsonObject["status"].toString() == "success") {
+ // figure out which user this is for
+
+ const QString PUBLIC_KEY_URL_REGEX_STRING = "api\\/v1\\/users\\/([A-Za-z0-9_\\.]+)\\/public_key";
+ QRegExp usernameRegex(PUBLIC_KEY_URL_REGEX_STRING);
+
+ if (usernameRegex.indexIn(requestReply.url().toString()) != -1) {
+ QString username = usernameRegex.cap(1);
+
+ qDebug() << "Storing a public key for user" << username;
+
+ // pull the public key as a QByteArray from this response
+ const QString JSON_DATA_KEY = "data";
+ const QString JSON_PUBLIC_KEY_KEY = "public_key";
+
+ _userPublicKeys[username] =
+ QByteArray::fromBase64(jsonObject[JSON_DATA_KEY].toObject()[JSON_PUBLIC_KEY_KEY].toString().toUtf8());
+ }
+ }
}
void DomainServer::transactionJSONCallback(const QJsonObject& data) {
@@ -1095,9 +1201,13 @@ void DomainServer::processDatagram(const QByteArray& receivedPacket, const HifiS
if (!nodeUUID.isNull() && nodeList->nodeWithUUID(nodeUUID)) {
NodeType_t throwawayNodeType;
HifiSockAddr nodePublicAddress, nodeLocalAddress;
+
+ QDataStream packetStream(receivedPacket);
+ packetStream.skipRawData(numBytesForPacketHeader(receivedPacket));
- int numNodeInfoBytes = parseNodeDataFromByteArray(throwawayNodeType, nodePublicAddress, nodeLocalAddress,
- receivedPacket, senderSockAddr);
+ int numNodeInfoBytes = parseNodeDataFromByteArray(packetStream, throwawayNodeType,
+ nodePublicAddress, nodeLocalAddress,
+ senderSockAddr);
SharedNodePointer checkInNode = nodeList->updateSocketsForNode(nodeUUID, nodePublicAddress, nodeLocalAddress);
@@ -1545,13 +1655,6 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
// we've redirected the user back to our homepage
return true;
- } else {
- qDebug() << "Requesting a token for user with session UUID" << uuidStringWithoutCurlyBraces(stateUUID);
-
- // insert this to our pending token replies so we can associate the returned access token with the right UUID
- _networkReplyUUIDMap.insert(tokenReply, stateUUID);
-
- connect(tokenReply, &QNetworkReply::finished, this, &DomainServer::handleTokenRequestFinished);
}
}
@@ -1695,22 +1798,6 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
const QString OAUTH_JSON_ACCESS_TOKEN_KEY = "access_token";
-void DomainServer::handleTokenRequestFinished() {
- QNetworkReply* networkReply = reinterpret_cast(sender());
- QUuid matchingSessionUUID = _networkReplyUUIDMap.take(networkReply);
-
- if (!matchingSessionUUID.isNull() && networkReply->error() == QNetworkReply::NoError) {
-
- qDebug() << "Received access token for user with UUID" << uuidStringWithoutCurlyBraces(matchingSessionUUID)
- << "-" << "requesting profile.";
-
- QNetworkReply* profileReply = profileRequestGivenTokenReply(networkReply);
-
- connect(profileReply, &QNetworkReply::finished, this, &DomainServer::handleProfileRequestFinished);
-
- _networkReplyUUIDMap.insert(profileReply, matchingSessionUUID);
- }
-}
QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenReply) {
// pull the access token from the returned JSON and store it with the matching session UUID
@@ -1719,54 +1806,12 @@ QNetworkReply* DomainServer::profileRequestGivenTokenReply(QNetworkReply* tokenR
// fire off a request to get this user's identity so we can see if we will let them in
QUrl profileURL = _oauthProviderURL;
- profileURL.setPath("/api/v1/users/profile");
+ profileURL.setPath("/api/v1/user/profile");
profileURL.setQuery(QString("%1=%2").arg(OAUTH_JSON_ACCESS_TOKEN_KEY, accessToken));
return NetworkAccessManager::getInstance().get(QNetworkRequest(profileURL));
}
-void DomainServer::handleProfileRequestFinished() {
- QNetworkReply* networkReply = reinterpret_cast(sender());
- QUuid matchingSessionUUID = _networkReplyUUIDMap.take(networkReply);
-
- if (!matchingSessionUUID.isNull() && networkReply->error() == QNetworkReply::NoError) {
- QJsonDocument profileJSON = QJsonDocument::fromJson(networkReply->readAll());
-
- if (profileJSON.object()["status"].toString() == "success") {
- // pull the user roles from the response
- QJsonArray userRolesArray = profileJSON.object()["data"].toObject()["user"].toObject()["roles"].toArray();
-
- QStringList allowedRolesArray = _settingsManager.getSettingsMap().value(ALLOWED_ROLES_CONFIG_KEY).toStringList();
-
- QString connectableUsername;
- QString profileUsername = profileJSON.object()["data"].toObject()["user"].toObject()["username"].toString();
-
- foreach(const QJsonValue& roleValue, userRolesArray) {
- if (allowedRolesArray.contains(roleValue.toString())) {
- // the user has a role that lets them in
- // set the bool to true and break
- connectableUsername = profileUsername;
- break;
- }
- }
-
- if (connectableUsername.isEmpty()) {
- qDebug() << "User" << profileUsername << "with session UUID"
- << uuidStringWithoutCurlyBraces(matchingSessionUUID)
- << "does not have an allowable role. Refusing connection.";
- } else {
- qDebug() << "User" << profileUsername << "with session UUID"
- << uuidStringWithoutCurlyBraces(matchingSessionUUID)
- << "has an allowable role. Can connect.";
- }
-
- // insert this UUID and a flag that indicates if they are allowed to connect
- _sessionAuthenticationHash.insert(matchingSessionUUID, connectableUsername);
- }
- }
-}
-
-
const QString DS_SETTINGS_SESSIONS_GROUP = "web-sessions";
Headers DomainServer::setupCookieHeadersFromProfileReply(QNetworkReply* profileReply) {
diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h
index 0ad2aae8a8..5e4da00601 100644
--- a/domain-server/src/DomainServer.h
+++ b/domain-server/src/DomainServer.h
@@ -52,6 +52,7 @@ public slots:
/// Called by NodeList to inform us a node has been killed
void nodeKilled(SharedNodePointer node);
+ void publicKeyJSONCallback(QNetworkReply& requestReply);
void transactionJSONCallback(const QJsonObject& data);
void restart();
@@ -82,8 +83,17 @@ private:
void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr);
void handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr);
- int parseNodeDataFromByteArray(NodeType_t& nodeType, HifiSockAddr& publicSockAddr,
- HifiSockAddr& localSockAddr, const QByteArray& packet, const HifiSockAddr& senderSockAddr);
+ bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature,
+ const HifiSockAddr& senderSockAddr);
+
+ void preloadAllowedUserPublicKeys();
+ void requestUserPublicKey(const QString& username);
+
+ int parseNodeDataFromByteArray(QDataStream& packetStream,
+ NodeType_t& nodeType,
+ HifiSockAddr& publicSockAddr,
+ HifiSockAddr& localSockAddr,
+ const HifiSockAddr& senderSockAddr);
NodeSet nodeInterestListFromPacket(const QByteArray& packet, int numPreceedingBytes);
void sendDomainListToNode(const SharedNodePointer& node, const HifiSockAddr& senderSockAddr,
const NodeSet& nodeInterestList);
@@ -131,13 +141,11 @@ private:
QString _oauthClientID;
QString _oauthClientSecret;
QString _hostname;
- QMap _networkReplyUUIDMap;
- QHash _sessionAuthenticationHash;
QSet _webAuthenticationStateSet;
QHash _cookieSessionHash;
- HifiSockAddr _localSockAddr;
+ QHash _userPublicKeys;
QHash _connectingICEPeers;
QHash _connectedICEPeers;
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index cab75aab0a..a85181b89e 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -105,7 +105,6 @@ link_hifi_libraries(shared octree voxels fbx metavoxels networking particles ent
# find any optional and required libraries
find_package(ZLIB REQUIRED)
-find_package(OpenSSL REQUIRED)
# perform standard include and linking for found externals
foreach(EXTERNAL ${OPTIONAL_EXTERNALS})
@@ -169,10 +168,9 @@ endif ()
# include headers for interface and InterfaceConfig.
include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes")
-include_directories("${OPENSSL_INCLUDE_DIR}")
target_link_libraries(
- ${TARGET_NAME} ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES}
+ ${TARGET_NAME} ${ZLIB_LIBRARIES}
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets
)
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index b7da4903e3..b85e1e4440 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -72,7 +72,6 @@
#include "InterfaceVersion.h"
#include "Menu.h"
#include "ModelUploader.h"
-#include "PaymentManager.h"
#include "Util.h"
#include "devices/MIDIManager.h"
#include "devices/OculusManager.h"
@@ -90,7 +89,6 @@
#include "scripting/WindowScriptingInterface.h"
#include "ui/InfoView.h"
-#include "ui/OAuthWebViewHandler.h"
#include "ui/Snapshot.h"
#include "ui/Stats.h"
#include "ui/TextRenderer.h"
@@ -220,10 +218,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
listenPort = atoi(portStr);
}
- // call the OAuthWebviewHandler static getter so that its instance lives in our thread
- // make sure it is ready before the NodeList might need it
- OAuthWebViewHandler::getInstance();
-
// start the nodeThread so its event loop is running
_nodeThread->start();
@@ -256,11 +250,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived);
connect(&domainHandler, &DomainHandler::hostnameChanged, Menu::getInstance(), &Menu::clearLoginDialogDisplayedFlag);
- // hookup VoxelEditSender to PaymentManager so we can pay for octree edits
- const PaymentManager& paymentManager = PaymentManager::getInstance();
- connect(&_voxelEditSender, &VoxelEditPacketSender::octreePaymentRequired,
- &paymentManager, &PaymentManager::sendSignedPayment);
-
// update our location every 5 seconds in the data-server, assuming that we are authenticated with one
const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000;
@@ -3483,7 +3472,7 @@ void Application::updateLocationInServer() {
rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject);
- accountManager.authenticatedRequest("/api/v1/users/location", QNetworkAccessManager::PutOperation,
+ accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), QJsonDocument(rootObject).toJson());
}
}
@@ -3526,20 +3515,18 @@ void Application::domainChanged(const QString& domainHostname) {
// reset the voxels renderer
_voxels.killLocalVoxels();
-
- // reset the auth URL for OAuth web view handler
- OAuthWebViewHandler::getInstance().clearLastAuthorizationURL();
}
void Application::connectedToDomain(const QString& hostname) {
AccountManager& accountManager = AccountManager::getInstance();
+ const QUuid& domainID = NodeList::getInstance()->getDomainHandler().getUUID();
+
+ if (accountManager.isLoggedIn() && !domainID.isNull()) {
+ // update our data-server with the domain-server we're logged in with
- if (accountManager.isLoggedIn()) {
- // update our domain-server with the data-server we're logged in with
+ QString domainPutJsonString = "{\"location\":{\"domain_id\":\"" + uuidStringWithoutCurlyBraces(domainID) + "\"}}";
- QString domainPutJsonString = "{\"address\":{\"domain\":\"" + hostname + "\"}}";
-
- accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
+ accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), domainPutJsonString.toUtf8());
}
}
diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp
index 0889007c76..0232e0e71d 100644
--- a/interface/src/DatagramProcessor.cpp
+++ b/interface/src/DatagramProcessor.cpp
@@ -11,11 +11,11 @@
#include
+#include
#include
#include "Application.h"
#include "Menu.h"
-#include "ui/OAuthWebViewHandler.h"
#include "DatagramProcessor.h"
@@ -136,16 +136,11 @@ void DatagramProcessor::processDatagrams() {
application->_bandwidthMeter.inputStream(BandwidthMeter::AVATARS).updateValue(incomingPacket.size());
break;
}
- case PacketTypeDomainOAuthRequest: {
- QDataStream readStream(incomingPacket);
- readStream.skipRawData(numBytesForPacketHeader(incomingPacket));
-
- QUrl authorizationURL;
- readStream >> authorizationURL;
-
- QMetaObject::invokeMethod(&OAuthWebViewHandler::getInstance(), "displayWebviewForAuthorizationURL",
- Q_ARG(const QUrl&, authorizationURL));
-
+ case PacketTypeDomainConnectionDenied: {
+ // output to the log so the user knows they got a denied connection request
+ // and check and signal for an access token so that we can make sure they are logged in
+ qDebug() << "The domain-server denied a connection request.";
+ AccountManager::getInstance().checkAndSignalForAccessToken();
break;
}
case PacketTypeMuteEnvironment: {
diff --git a/interface/src/ModelUploader.cpp b/interface/src/ModelUploader.cpp
index f11d035ebe..7077c44287 100644
--- a/interface/src/ModelUploader.cpp
+++ b/interface/src/ModelUploader.cpp
@@ -364,7 +364,9 @@ void ModelUploader::send() {
_progressBar = NULL;
}
-void ModelUploader::checkJSON(const QJsonObject& jsonResponse) {
+void ModelUploader::checkJSON(QNetworkReply& requestReply) {
+ QJsonObject jsonResponse = QJsonDocument::fromJson(requestReply.readAll()).object();
+
if (jsonResponse.contains("status") && jsonResponse.value("status").toString() == "success") {
qDebug() << "status : success";
JSONCallbackParameters callbackParams;
@@ -426,7 +428,7 @@ void ModelUploader::uploadUpdate(qint64 bytesSent, qint64 bytesTotal) {
}
}
-void ModelUploader::uploadSuccess(const QJsonObject& jsonResponse) {
+void ModelUploader::uploadSuccess(QNetworkReply& requestReply) {
if (_progressDialog) {
_progressDialog->accept();
}
diff --git a/interface/src/ModelUploader.h b/interface/src/ModelUploader.h
index a1c7a27393..7d8ad2b526 100644
--- a/interface/src/ModelUploader.h
+++ b/interface/src/ModelUploader.h
@@ -40,9 +40,9 @@ public slots:
void send();
private slots:
- void checkJSON(const QJsonObject& jsonResponse);
+ void checkJSON(QNetworkReply& requestReply);
void uploadUpdate(qint64 bytesSent, qint64 bytesTotal);
- void uploadSuccess(const QJsonObject& jsonResponse);
+ void uploadSuccess(QNetworkReply& requestReply);
void uploadFailed(QNetworkReply& errorReply);
void checkS3();
void processCheck();
diff --git a/interface/src/PaymentManager.cpp b/interface/src/PaymentManager.cpp
deleted file mode 100644
index a0c05f34b3..0000000000
--- a/interface/src/PaymentManager.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//
-// PaymentManager.cpp
-// interface/src
-//
-// Created by Stephen Birarda on 2014-07-30.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include "SignedWalletTransaction.h"
-
-#include "PaymentManager.h"
-
-PaymentManager& PaymentManager::getInstance() {
- static PaymentManager sharedInstance;
- return sharedInstance;
-}
-
-void PaymentManager::sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID) {
-
- QByteArray walletPrivateKeyByteArray = Menu::getInstance()->getWalletPrivateKey();
-
- if (!walletPrivateKeyByteArray.isEmpty()) {
- // setup a signed wallet transaction
- const qint64 DEFAULT_TRANSACTION_EXPIRY_SECONDS = 60;
- qint64 currentTimestamp = QDateTime::currentDateTimeUtc().toTime_t();
- SignedWalletTransaction newTransaction(destinationWalletUUID, satoshiAmount,
- currentTimestamp, DEFAULT_TRANSACTION_EXPIRY_SECONDS);
-
- // send the signed transaction to the redeeming node
- QByteArray transactionByteArray = byteArrayWithPopulatedHeader(PacketTypeSignedTransactionPayment);
-
- // append the binary message and the signed message digest
- transactionByteArray.append(newTransaction.binaryMessage());
- QByteArray signedMessageDigest = newTransaction.signedMessageDigest();
-
- if (!signedMessageDigest.isEmpty()) {
- transactionByteArray.append(signedMessageDigest);
-
- qDebug() << "Paying" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID;
-
- // use the NodeList to send that to the right node
- NodeList* nodeList = NodeList::getInstance();
- nodeList->writeDatagram(transactionByteArray, nodeList->nodeWithUUID(nodeUUID));
- } else {
- qDebug() << "Payment of" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID <<
- "cannot be sent because there was an error signing the transaction.";
- }
-
- } else {
- qDebug() << "Payment of" << satoshiAmount << "satoshis to" << destinationWalletUUID << "via" << nodeUUID <<
- "cannot be sent because there is no stored wallet private key.";
- }
-}
\ No newline at end of file
diff --git a/interface/src/PaymentManager.h b/interface/src/PaymentManager.h
deleted file mode 100644
index 67419a39a4..0000000000
--- a/interface/src/PaymentManager.h
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// PaymentManager.h
-// interface/src
-//
-// Created by Stephen Birarda on 2014-07-30.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_PaymentManager_h
-#define hifi_PaymentManager_h
-
-#include
-
-class PaymentManager : public QObject {
- Q_OBJECT
-public:
- static PaymentManager& getInstance();
-public slots:
- void sendSignedPayment(qint64 satoshiAmount, const QUuid& nodeUUID, const QUuid& destinationWalletUUID);
-};
-
-#endif // hifi_PaymentManager_h
\ No newline at end of file
diff --git a/interface/src/SignedWalletTransaction.cpp b/interface/src/SignedWalletTransaction.cpp
deleted file mode 100644
index 8a0d4e6fdb..0000000000
--- a/interface/src/SignedWalletTransaction.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//
-// SignedWalletTransaction.cpp
-// interface/src
-//
-// Created by Stephen Birarda on 2014-07-11.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-
-#include "Menu.h"
-
-#include "SignedWalletTransaction.h"
-
-SignedWalletTransaction::SignedWalletTransaction(const QUuid& destinationUUID, qint64 amount,
- qint64 messageTimestamp, qint64 expiryDelta) :
- WalletTransaction(destinationUUID, amount),
- _messageTimestamp(messageTimestamp),
- _expiryDelta(expiryDelta)
-{
-
-}
-
-QByteArray SignedWalletTransaction::binaryMessage() {
- // build the message using the components of this transaction
-
- // UUID, source UUID, destination UUID, message timestamp, expiry delta, amount
- QByteArray messageBinary;
-
- messageBinary.append(_uuid.toRfc4122());
-
- messageBinary.append(reinterpret_cast(&_messageTimestamp), sizeof(_messageTimestamp));
- messageBinary.append(reinterpret_cast(&_expiryDelta), sizeof(_expiryDelta));
-
- messageBinary.append(AccountManager::getInstance().getAccountInfo().getWalletID().toRfc4122());
-
- messageBinary.append(_destinationUUID.toRfc4122());
-
- messageBinary.append(reinterpret_cast(&_amount), sizeof(_amount));
-
- return messageBinary;
-}
-
-QByteArray SignedWalletTransaction::hexMessage() {
- return binaryMessage().toHex();
-}
-
-QByteArray SignedWalletTransaction::messageDigest() {
- return QCryptographicHash::hash(hexMessage(), QCryptographicHash::Sha256).toHex();
-}
-
-QByteArray SignedWalletTransaction::signedMessageDigest() {
- // pull the current private key from menu into RSA structure in memory
- QByteArray privateKeyByteArray = Menu::getInstance()->getWalletPrivateKey();
-
- BIO* privateKeyBIO = NULL;
- RSA* rsaPrivateKey = NULL;
-
- privateKeyBIO = BIO_new_mem_buf(privateKeyByteArray.data(), privateKeyByteArray.size());
- PEM_read_bio_RSAPrivateKey(privateKeyBIO, &rsaPrivateKey, NULL, NULL);
-
- QByteArray digestToEncrypt = messageDigest();
- QByteArray encryptedDigest(RSA_size(rsaPrivateKey), 0);
-
- int encryptReturn = RSA_private_encrypt(digestToEncrypt.size(),
- reinterpret_cast(digestToEncrypt.constData()),
- reinterpret_cast(encryptedDigest.data()),
- rsaPrivateKey, RSA_PKCS1_PADDING);
-
- // free the two structures used
- BIO_free(privateKeyBIO);
- RSA_free(rsaPrivateKey);
-
- return (encryptReturn != -1) ? encryptedDigest : QByteArray();
-}
\ No newline at end of file
diff --git a/interface/src/SignedWalletTransaction.h b/interface/src/SignedWalletTransaction.h
deleted file mode 100644
index 6bc66a535e..0000000000
--- a/interface/src/SignedWalletTransaction.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// SignedWalletTransaction.h
-// interfac/src
-//
-// Created by Stephen Birarda on 2014-07-11.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_SignedWalletTransaction_h
-#define hifi_SignedWalletTransaction_h
-
-#include
-
-class SignedWalletTransaction : public WalletTransaction {
- Q_OBJECT
-public:
- SignedWalletTransaction(const QUuid& destinationUUID, qint64 amount, qint64 messageTimestamp, qint64 expiryDelta);
-
- QByteArray binaryMessage();
- QByteArray hexMessage();
- QByteArray messageDigest();
- QByteArray signedMessageDigest();
-
-private:
- qint64 _messageTimestamp;
- qint64 _expiryDelta;
-};
-
-#endif // hifi_SignedWalletTransaction_h
\ No newline at end of file
diff --git a/interface/src/devices/Joystick.cpp b/interface/src/devices/Joystick.cpp
index 5446ca1330..25b8bc142d 100644
--- a/interface/src/devices/Joystick.cpp
+++ b/interface/src/devices/Joystick.cpp
@@ -20,10 +20,10 @@
const float MAX_AXIS = 32768.0f;
Joystick::Joystick(SDL_JoystickID instanceId, const QString& name, SDL_GameController* sdlGameController) :
- _instanceId(instanceId),
- _name(name),
_sdlGameController(sdlGameController),
_sdlJoystick(SDL_GameControllerGetJoystick(_sdlGameController)),
+ _instanceId(instanceId),
+ _name(name),
_axes(QVector(SDL_JoystickNumAxes(_sdlJoystick))),
_buttons(QVector(SDL_JoystickNumButtons(_sdlJoystick)))
{
diff --git a/interface/src/ui/OAuthWebViewHandler.cpp b/interface/src/ui/OAuthWebViewHandler.cpp
deleted file mode 100644
index 86db54afb4..0000000000
--- a/interface/src/ui/OAuthWebViewHandler.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
-//
-// OAuthWebViewHandler.cpp
-// interface/src/ui
-//
-// Created by Stephen Birarda on 2014-05-01.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#include
-#include
-
-#include
-
-#include "Application.h"
-
-#include "OAuthWebViewHandler.h"
-
-OAuthWebViewHandler& OAuthWebViewHandler::getInstance() {
- static OAuthWebViewHandler sharedInstance;
- return sharedInstance;
-}
-
-OAuthWebViewHandler::OAuthWebViewHandler() :
- _activeWebView(NULL),
- _webViewRedisplayTimer(),
- _lastAuthorizationURL()
-{
- addHighFidelityRootCAToSSLConfig();
-}
-
-const char HIGH_FIDELITY_CA[] = "-----BEGIN CERTIFICATE-----\n"
- "MIID6TCCA1KgAwIBAgIJANlfRkRD9A8bMA0GCSqGSIb3DQEBBQUAMIGqMQswCQYD\n"
- "VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j\n"
- "aXNjbzEbMBkGA1UEChMSSGlnaCBGaWRlbGl0eSwgSW5jMRMwEQYDVQQLEwpPcGVy\n"
- "YXRpb25zMRgwFgYDVQQDEw9oaWdoZmlkZWxpdHkuaW8xIjAgBgkqhkiG9w0BCQEW\n"
- "E29wc0BoaWdoZmlkZWxpdHkuaW8wHhcNMTQwMzI4MjIzMzM1WhcNMjQwMzI1MjIz\n"
- "MzM1WjCBqjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNV\n"
- "BAcTDVNhbiBGcmFuY2lzY28xGzAZBgNVBAoTEkhpZ2ggRmlkZWxpdHksIEluYzET\n"
- "MBEGA1UECxMKT3BlcmF0aW9uczEYMBYGA1UEAxMPaGlnaGZpZGVsaXR5LmlvMSIw\n"
- "IAYJKoZIhvcNAQkBFhNvcHNAaGlnaGZpZGVsaXR5LmlvMIGfMA0GCSqGSIb3DQEB\n"
- "AQUAA4GNADCBiQKBgQDyo1euYiPPEdnvDZnIjWrrP230qUKMSj8SWoIkbTJF2hE8\n"
- "2eP3YOgbgSGBzZ8EJBxIOuNmj9g9Eg6691hIKFqy5W0BXO38P04Gg+pVBvpHFGBi\n"
- "wpqGbfsjaUDuYmBeJRcMO0XYkLCRQG+lAQNHoFDdItWAJfC3FwtP3OCDnz8cNwID\n"
- "AQABo4IBEzCCAQ8wHQYDVR0OBBYEFCSv2kmiGg6VFMnxXzLDNP304cPAMIHfBgNV\n"
- "HSMEgdcwgdSAFCSv2kmiGg6VFMnxXzLDNP304cPAoYGwpIGtMIGqMQswCQYDVQQG\n"
- "EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\n"
- "bzEbMBkGA1UEChMSSGlnaCBGaWRlbGl0eSwgSW5jMRMwEQYDVQQLEwpPcGVyYXRp\n"
- "b25zMRgwFgYDVQQDEw9oaWdoZmlkZWxpdHkuaW8xIjAgBgkqhkiG9w0BCQEWE29w\n"
- "c0BoaWdoZmlkZWxpdHkuaW+CCQDZX0ZEQ/QPGzAMBgNVHRMEBTADAQH/MA0GCSqG\n"
- "SIb3DQEBBQUAA4GBAEkQl3p+lH5vuoCNgyfa67nL0MsBEt+5RSBOgjwCjjASjzou\n"
- "FTv5w0he2OypgMQb8i/BYtS1lJSFqjPJcSM1Salzrm3xDOK5pOXJ7h6SQLPDVEyf\n"
- "Hy2/9d/to+99+SOUlvfzfgycgjOc+s/AV7Y+GBd7uzGxUdrN4egCZW1F6/mH\n"
- "-----END CERTIFICATE-----\n";
-
-void OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig() {
- QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
-
- // add the High Fidelity root CA to the list of trusted CA certificates
- QByteArray highFidelityCACertificate(HIGH_FIDELITY_CA, sizeof(HIGH_FIDELITY_CA));
- sslConfig.setCaCertificates(sslConfig.caCertificates() + QSslCertificate::fromData(highFidelityCACertificate));
-
- // set the modified configuration
- QSslConfiguration::setDefaultConfiguration(sslConfig);
-}
-
-const int WEB_VIEW_REDISPLAY_ELAPSED_MSECS = 5 * 1000;
-
-void OAuthWebViewHandler::displayWebviewForAuthorizationURL(const QUrl& authorizationURL) {
- if (!_activeWebView) {
-
- if (!_lastAuthorizationURL.isEmpty()) {
- if (_lastAuthorizationURL.host() == authorizationURL.host()
- && _webViewRedisplayTimer.elapsed() < WEB_VIEW_REDISPLAY_ELAPSED_MSECS) {
- // this would be re-displaying an OAuth dialog for the same auth URL inside of the redisplay ms
- // so return instead
- return;
- }
- }
-
- _lastAuthorizationURL = authorizationURL;
-
- _activeWebView = new QWebView;
-
- // keep the window on top and delete it when it closes
- _activeWebView->setWindowFlags(Qt::Sheet);
- _activeWebView->setAttribute(Qt::WA_DeleteOnClose);
-
- qDebug() << "Displaying QWebView for OAuth authorization at" << authorizationURL.toString();
-
- AccountManager& accountManager = AccountManager::getInstance();
-
- QUrl codedAuthorizationURL = authorizationURL;
-
- // check if we have an access token for this host - if so we can bypass login by adding it to the URL
- if (accountManager.getAuthURL().host() == authorizationURL.host()
- && accountManager.hasValidAccessToken()) {
-
- const QString ACCESS_TOKEN_QUERY_STRING_KEY = "access_token";
-
- QUrlQuery authQuery(codedAuthorizationURL);
- authQuery.addQueryItem(ACCESS_TOKEN_QUERY_STRING_KEY, accountManager.getAccountInfo().getAccessToken().token);
-
- codedAuthorizationURL.setQuery(authQuery);
- }
-
- connect(_activeWebView.data(), &QWebView::urlChanged, this, &OAuthWebViewHandler::handleURLChanged);
-
- _activeWebView->load(codedAuthorizationURL);
-
- connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::sslErrors,
- this, &OAuthWebViewHandler::handleSSLErrors);
- connect(_activeWebView->page()->networkAccessManager(), &QNetworkAccessManager::finished,
- this, &OAuthWebViewHandler::handleReplyFinished);
- connect(_activeWebView.data(), &QWebView::loadFinished, this, &OAuthWebViewHandler::handleLoadFinished);
-
- // connect to the destroyed signal so after the web view closes we can start a timer
- connect(_activeWebView.data(), &QWebView::destroyed, this, &OAuthWebViewHandler::handleWebViewDestroyed);
- }
-}
-
-void OAuthWebViewHandler::handleSSLErrors(QNetworkReply* networkReply, const QList& errorList) {
- qDebug() << "SSL Errors:" << errorList;
-}
-
-void OAuthWebViewHandler::handleLoadFinished(bool success) {
- if (success && _activeWebView->url().host() == NodeList::getInstance()->getDomainHandler().getHostname()) {
- qDebug() << "OAuth authorization code passed successfully to domain-server.";
-
- // grab the UUID that is set as the state parameter in the auth URL
- // since that is our new session UUID
- QUrlQuery authQuery(_activeWebView->url());
-
- const QString AUTH_STATE_QUERY_KEY = "state";
- NodeList::getInstance()->setSessionUUID(QUuid(authQuery.queryItemValue(AUTH_STATE_QUERY_KEY)));
-
- _activeWebView->close();
- _activeWebView = NULL;
- }
-}
-
-void OAuthWebViewHandler::handleReplyFinished(QNetworkReply* reply) {
- if (_activeWebView && reply->error() != QNetworkReply::NoError) {
- qDebug() << "Error loading" << reply->url() << "-" << reply->errorString();
- _activeWebView->close();
- }
-}
-
-void OAuthWebViewHandler::handleWebViewDestroyed(QObject* destroyedObject) {
- _webViewRedisplayTimer.restart();
-}
-
-void OAuthWebViewHandler::handleURLChanged(const QUrl& url) {
- // check if this is the authorization screen - if it is then we need to show the OAuthWebViewHandler
- const QString ACCESS_TOKEN_URL_REGEX_STRING = "redirect_uri=[\\w:\\/\\.]+&access_token=";
- QRegExp accessTokenRegex(ACCESS_TOKEN_URL_REGEX_STRING);
-
- if (accessTokenRegex.indexIn(url.toString()) != -1) {
- _activeWebView->show();
- } else if (url.toString() == DEFAULT_NODE_AUTH_URL.toString() + "/login") {
- // this is a login request - we're going to close the webview and signal the AccountManager that we need a login
- qDebug() << "data-server replied with login request. Signalling that login is required to proceed with OAuth.";
- _activeWebView->close();
- AccountManager::getInstance().checkAndSignalForAccessToken();
- }
-}
diff --git a/interface/src/ui/OAuthWebViewHandler.h b/interface/src/ui/OAuthWebViewHandler.h
deleted file mode 100644
index 1a95f17dfd..0000000000
--- a/interface/src/ui/OAuthWebViewHandler.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// OAuthWebviewHandler.h
-// interface/src/ui
-//
-// Created by Stephen Birarda on 2014-05-01.
-// Copyright 2014 High Fidelity, Inc.
-//
-// Distributed under the Apache License, Version 2.0.
-// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
-//
-
-#ifndef hifi_OAuthWebviewHandler_h
-#define hifi_OAuthWebviewHandler_h
-
-#include
-
-class QWebView;
-
-class OAuthWebViewHandler : public QObject {
- Q_OBJECT
-public:
- OAuthWebViewHandler();
- static OAuthWebViewHandler& getInstance();
- static void addHighFidelityRootCAToSSLConfig();
-
- void clearLastAuthorizationURL() { _lastAuthorizationURL = QUrl(); }
-
-public slots:
- void displayWebviewForAuthorizationURL(const QUrl& authorizationURL);
-
-private slots:
- void handleSSLErrors(QNetworkReply* networkReply, const QList& errorList);
- void handleLoadFinished(bool success);
- void handleReplyFinished(QNetworkReply* reply);
- void handleWebViewDestroyed(QObject* destroyedObject);
- void handleURLChanged(const QUrl& url);
-private:
- QPointer _activeWebView;
- QElapsedTimer _webViewRedisplayTimer;
- QUrl _lastAuthorizationURL;
-};
-
-#endif // hifi_OAuthWebviewHandler_h
\ No newline at end of file
diff --git a/libraries/networking/CMakeLists.txt b/libraries/networking/CMakeLists.txt
index 501437fab2..e4dd37234b 100644
--- a/libraries/networking/CMakeLists.txt
+++ b/libraries/networking/CMakeLists.txt
@@ -10,5 +10,19 @@ if (WIN32)
target_link_libraries(${TARGET_NAME} ws2_32.lib)
endif ()
+# find OpenSSL
+find_package(OpenSSL REQUIRED)
+
+if (APPLE AND ${OPENSSL_INCLUDE_DIR} STREQUAL "/usr/include")
+ # this is a user on OS X using system OpenSSL, which is going to throw warnings since they're deprecating for their common crypto
+ message(WARNING "The found version of OpenSSL is the OS X system version. This will produce deprecation warnings."
+ "\nWe recommend you install a newer version (at least 1.0.1h) in a different directory and set OPENSSL_ROOT_DIR in your env so Cmake can find it.")
+endif ()
+
+include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
+
+# append OpenSSL to our list of libraries to link
+list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${OPENSSL_LIBRARIES}")
+
# call macro to link our dependencies and bubble them up via a property on our target
link_shared_dependencies()
\ No newline at end of file
diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp
index bb471442ea..650e0e3321 100644
--- a/libraries/networking/src/AccountManager.cpp
+++ b/libraries/networking/src/AccountManager.cpp
@@ -19,9 +19,11 @@
#include
#include
#include
+#include
#include "NodeList.h"
#include "PacketHeaders.h"
+#include "RSAKeypairGenerator.h"
#include "AccountManager.h"
@@ -144,6 +146,12 @@ void AccountManager::setAuthURL(const QUrl& authURL) {
} else {
requestProfile();
}
+
+ // if we don't have a private key in settings we should generate a new keypair
+ if (!_accountInfo.hasPrivateKey()) {
+ qDebug() << "No private key present - generating a new key-pair.";
+ generateNewKeypair();
+ }
}
}
}
@@ -280,14 +288,12 @@ void AccountManager::processReply() {
}
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
- QJsonDocument jsonResponse = QJsonDocument::fromJson(requestReply->readAll());
-
JSONCallbackParameters callbackParams = _pendingCallbackMap.value(requestReply);
if (callbackParams.jsonCallbackReceiver) {
// invoke the right method on the callback receiver
QMetaObject::invokeMethod(callbackParams.jsonCallbackReceiver, qPrintable(callbackParams.jsonCallbackMethod),
- Q_ARG(const QJsonObject&, jsonResponse.object()));
+ Q_ARG(QNetworkReply&, *requestReply));
// remove the related reply-callback group from the map
_pendingCallbackMap.remove(requestReply);
@@ -295,7 +301,7 @@ void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
} else {
if (VERBOSE_HTTP_REQUEST_DEBUGGING) {
qDebug() << "Received JSON response from data-server that has no matching callback.";
- qDebug() << jsonResponse;
+ qDebug() << QJsonDocument::fromJson(requestReply->readAll());
}
}
}
@@ -319,6 +325,16 @@ void AccountManager::passErrorToCallback(QNetworkReply* requestReply) {
}
}
+void AccountManager::persistAccountToSettings() {
+ if (_shouldPersistToSettingsFile) {
+ // store this access token into the local settings
+ QSettings localSettings;
+ localSettings.beginGroup(ACCOUNTS_GROUP);
+ localSettings.setValue(_authURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
+ QVariant::fromValue(_accountInfo));
+ }
+}
+
bool AccountManager::hasValidAccessToken() {
if (_accountInfo.getAccessToken().token.isEmpty() || _accountInfo.getAccessToken().isExpired()) {
@@ -408,15 +424,10 @@ void AccountManager::requestAccessTokenFinished() {
emit loginComplete(rootURL);
- if (_shouldPersistToSettingsFile) {
- // store this access token into the local settings
- QSettings localSettings;
- localSettings.beginGroup(ACCOUNTS_GROUP);
- localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
- QVariant::fromValue(_accountInfo));
- }
+ persistAccountToSettings();
requestProfile();
+ generateNewKeypair();
}
} else {
// TODO: error handling
@@ -434,7 +445,7 @@ void AccountManager::requestProfile() {
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
QUrl profileURL = _authURL;
- profileURL.setPath("/api/v1/users/profile");
+ profileURL.setPath("/api/v1/user/profile");
QNetworkRequest profileRequest(profileURL);
profileRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue());
@@ -458,15 +469,8 @@ void AccountManager::requestProfileFinished() {
// the username has changed to whatever came back
emit usernameChanged(_accountInfo.getUsername());
- if (_shouldPersistToSettingsFile) {
- // store the whole profile into the local settings
- QUrl rootURL = profileReply->url();
- rootURL.setPath("");
- QSettings localSettings;
- localSettings.beginGroup(ACCOUNTS_GROUP);
- localSettings.setValue(rootURL.toString().replace("//", DOUBLE_SLASH_SUBSTITUTE),
- QVariant::fromValue(_accountInfo));
- }
+ // store the whole profile into the local settings
+ persistAccountToSettings();
} else {
// TODO: error handling
@@ -478,3 +482,57 @@ void AccountManager::requestProfileError(QNetworkReply::NetworkError error) {
// TODO: error handling
qDebug() << "AccountManager requestProfileError - " << error;
}
+
+void AccountManager::generateNewKeypair() {
+ // setup a new QThread to generate the keypair on, in case it takes a while
+ QThread* generateThread = new QThread(this);
+
+ // setup a keypair generator
+ RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator();
+
+ connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair);
+ connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair);
+ connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair,
+ this, &AccountManager::handleKeypairGenerationError);
+ connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit);
+ connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater);
+
+ keypairGenerator->moveToThread(generateThread);
+
+ qDebug() << "Starting worker thread to generate 2048-bit RSA key-pair.";
+ generateThread->start();
+}
+
+void AccountManager::processGeneratedKeypair(const QByteArray& publicKey, const QByteArray& privateKey) {
+
+ qDebug() << "Generated 2048-bit RSA key-pair. Storing private key and uploading public key.";
+
+ // set the private key on our data-server account info
+ _accountInfo.setPrivateKey(privateKey);
+ persistAccountToSettings();
+
+ // upload the public key so data-web has an up-to-date key
+ const QString PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
+
+ // setup a multipart upload to send up the public key
+ QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
+
+ QHttpPart keyPart;
+ keyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
+ keyPart.setHeader(QNetworkRequest::ContentDispositionHeader,
+ QVariant("form-data; name=\"public_key\"; filename=\"public_key\""));
+ keyPart.setBody(publicKey);
+
+ requestMultiPart->append(keyPart);
+
+ authenticatedRequest(PUBLIC_KEY_UPDATE_PATH, QNetworkAccessManager::PutOperation,
+ JSONCallbackParameters(), QByteArray(), requestMultiPart);
+
+ // get rid of the keypair generator now that we don't need it anymore
+ sender()->deleteLater();
+}
+
+void AccountManager::handleKeypairGenerationError() {
+ // for now there isn't anything we do with this except get the worker thread to clean up
+ sender()->deleteLater();
+}
diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h
index 3628b5a865..7b5ea8de8b 100644
--- a/libraries/networking/src/AccountManager.h
+++ b/libraries/networking/src/AccountManager.h
@@ -70,7 +70,7 @@ public:
void requestAccessToken(const QString& login, const QString& password);
void requestProfile();
- const DataServerAccountInfo& getAccountInfo() const { return _accountInfo; }
+ DataServerAccountInfo& getAccountInfo() { return _accountInfo; }
public slots:
void requestAccessTokenFinished();
@@ -91,13 +91,19 @@ signals:
void balanceChanged(qint64 newBalance);
private slots:
void processReply();
+ void handleKeypairGenerationError();
+ void processGeneratedKeypair(const QByteArray& publicKey, const QByteArray& privateKey);
private:
AccountManager();
AccountManager(AccountManager const& other); // not implemented
void operator=(AccountManager const& other); // not implemented
+
+ void persistAccountToSettings();
void passSuccessToCallback(QNetworkReply* reply);
void passErrorToCallback(QNetworkReply* reply);
+
+ void generateNewKeypair();
Q_INVOKABLE void invokedRequest(const QString& path,
bool requiresAuthentication,
diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp
index 3d7617e17b..1a7f6d3dbc 100644
--- a/libraries/networking/src/AddressManager.cpp
+++ b/libraries/networking/src/AddressManager.cpp
@@ -10,6 +10,7 @@
//
#include
+#include
#include
#include
@@ -134,8 +135,9 @@ void AddressManager::handleLookupString(const QString& lookupString) {
}
}
-void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) {
- QJsonObject dataObject = jsonObject["data"].toObject();
+void AddressManager::handleAPIResponse(QNetworkReply& requestReply) {
+ QJsonObject responseObject = QJsonDocument::fromJson(requestReply.readAll()).object();
+ QJsonObject dataObject = responseObject["data"].toObject();
const QString ADDRESS_API_DOMAIN_KEY = "domain";
const QString ADDRESS_API_ONLINE_KEY = "online";
@@ -190,7 +192,7 @@ void AddressManager::handleAPIResponse(const QJsonObject &jsonObject) {
} else {
qDebug() << "Received an address manager API response with no domain key. Cannot parse.";
- qDebug() << jsonObject;
+ qDebug() << responseObject;
}
} else {
// we've been told that this result exists but is offline, emit our signal so the application can handle
diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h
index fe6219b3f7..bc0f2716dd 100644
--- a/libraries/networking/src/AddressManager.h
+++ b/libraries/networking/src/AddressManager.h
@@ -42,7 +42,7 @@ public:
public slots:
void handleLookupString(const QString& lookupString);
- void handleAPIResponse(const QJsonObject& jsonObject);
+ void handleAPIResponse(QNetworkReply& requestReply);
void handleAPIError(QNetworkReply& errorReply);
void goToUser(const QString& username);
signals:
diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp
index 9bdb012f70..61b1bbf418 100644
--- a/libraries/networking/src/DataServerAccountInfo.cpp
+++ b/libraries/networking/src/DataServerAccountInfo.cpp
@@ -9,6 +9,9 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
+#include
+
+#include
#include
#include "DataServerAccountInfo.h"
@@ -20,7 +23,9 @@ DataServerAccountInfo::DataServerAccountInfo() :
_discourseApiKey(),
_walletID(),
_balance(0),
- _hasBalance(false)
+ _hasBalance(false),
+ _privateKey(),
+ _usernameSignature()
{
}
@@ -33,6 +38,7 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI
_walletID = otherInfo._walletID;
_balance = otherInfo._balance;
_hasBalance = otherInfo._hasBalance;
+ _privateKey = otherInfo._privateKey;
}
DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) {
@@ -51,6 +57,7 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) {
swap(_walletID, otherInfo._walletID);
swap(_balance, otherInfo._balance);
swap(_hasBalance, otherInfo._hasBalance);
+ swap(_privateKey, otherInfo._privateKey);
}
void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) {
@@ -61,6 +68,9 @@ void DataServerAccountInfo::setUsername(const QString& username) {
if (_username != username) {
_username = username;
+ // clear our username signature so it has to be re-created
+ _usernameSignature = QByteArray();
+
qDebug() << "Username changed to" << username;
}
}
@@ -92,7 +102,8 @@ void DataServerAccountInfo::setBalance(qint64 balance) {
}
}
-void DataServerAccountInfo::setBalanceFromJSON(const QJsonObject& jsonObject) {
+void DataServerAccountInfo::setBalanceFromJSON(QNetworkReply& requestReply) {
+ QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object();
if (jsonObject["status"].toString() == "success") {
qint64 balanceInSatoshis = jsonObject["data"].toObject()["wallet"].toObject()["balance"].toDouble();
setBalance(balanceInSatoshis);
@@ -111,12 +122,58 @@ void DataServerAccountInfo::setProfileInfoFromJSON(const QJsonObject& jsonObject
setWalletID(QUuid(user["wallet_id"].toString()));
}
+const QByteArray& DataServerAccountInfo::getUsernameSignature() {
+ if (_usernameSignature.isEmpty()) {
+ if (!_privateKey.isEmpty()) {
+ const char* privateKeyData = _privateKey.constData();
+ RSA* rsaPrivateKey = d2i_RSAPrivateKey(NULL,
+ reinterpret_cast(&privateKeyData),
+ _privateKey.size());
+ if (rsaPrivateKey) {
+ QByteArray usernameByteArray = _username.toUtf8();
+ _usernameSignature.resize(RSA_size(rsaPrivateKey));
+
+ int encryptReturn = RSA_private_encrypt(usernameByteArray.size(),
+ reinterpret_cast(usernameByteArray.constData()),
+ reinterpret_cast(_usernameSignature.data()),
+ rsaPrivateKey, RSA_PKCS1_PADDING);
+
+ if (encryptReturn == -1) {
+ qDebug() << "Error encrypting username signature.";
+ qDebug() << "Will re-attempt on next domain-server check in.";
+ _usernameSignature = QByteArray();
+ }
+
+ // free the private key RSA struct now that we are done with it
+ RSA_free(rsaPrivateKey);
+ } else {
+ qDebug() << "Could not create RSA struct from QByteArray private key.";
+ qDebug() << "Will re-attempt on next domain-server check in.";
+ }
+ } else {
+ qDebug() << "No private key present in DataServerAccountInfo. Re-log to generate new key.";
+ qDebug() << "Returning empty username signature.";
+ }
+ }
+
+ return _usernameSignature;
+}
+
+void DataServerAccountInfo::setPrivateKey(const QByteArray& privateKey) {
+ _privateKey = privateKey;
+
+ // clear our username signature so it has to be re-created
+ _usernameSignature = QByteArray();
+}
+
QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) {
- out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey << info._walletID;
+ out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey
+ << info._walletID << info._privateKey;
return out;
}
QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) {
- in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey >> info._walletID;
+ in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey
+ >> info._walletID >> info._privateKey;
return in;
}
diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h
index 91675594ad..9804bd755c 100644
--- a/libraries/networking/src/DataServerAccountInfo.h
+++ b/libraries/networking/src/DataServerAccountInfo.h
@@ -13,6 +13,7 @@
#define hifi_DataServerAccountInfo_h
#include
+#include
#include
#include "OAuthAccessToken.h"
@@ -41,13 +42,17 @@ public:
const QUuid& getWalletID() const { return _walletID; }
void setWalletID(const QUuid& walletID);
+
+ const QByteArray& getUsernameSignature();
+ bool hasPrivateKey() const { return !_privateKey.isEmpty(); }
+ void setPrivateKey(const QByteArray& privateKey);
qint64 getBalance() const { return _balance; }
float getBalanceInSatoshis() const { return _balance / SATOSHIS_PER_CREDIT; }
void setBalance(qint64 balance);
bool hasBalance() const { return _hasBalance; }
void setHasBalance(bool hasBalance) { _hasBalance = hasBalance; }
- Q_INVOKABLE void setBalanceFromJSON(const QJsonObject& jsonObject);
+ Q_INVOKABLE void setBalanceFromJSON(QNetworkReply& requestReply);
bool hasProfile() const;
@@ -67,6 +72,8 @@ private:
QUuid _walletID;
qint64 _balance;
bool _hasBalance;
+ QByteArray _privateKey;
+ QByteArray _usernameSignature;
};
#endif // hifi_DataServerAccountInfo_h
diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp
index dd33c96d74..919dc75c23 100644
--- a/libraries/networking/src/LimitedNodeList.cpp
+++ b/libraries/networking/src/LimitedNodeList.cpp
@@ -679,7 +679,6 @@ void LimitedNodeList::updateLocalSockAddr() {
qDebug() << "Local socket has changed from" << _localSockAddr << "to" << newSockAddr;
}
-
_localSockAddr = newSockAddr;
emit localSockAddrChanged(_localSockAddr);
diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h
index c416773201..73381d01a5 100644
--- a/libraries/networking/src/LimitedNodeList.h
+++ b/libraries/networking/src/LimitedNodeList.h
@@ -101,6 +101,8 @@ public:
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
SharedNodePointer updateSocketsForNode(const QUuid& uuid,
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket);
+
+ const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; }
void processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet);
void processKillNode(const QByteArray& datagram);
diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp
index 25531861ca..13ebfb59b8 100644
--- a/libraries/networking/src/NodeList.cpp
+++ b/libraries/networking/src/NodeList.cpp
@@ -302,11 +302,22 @@ void NodeList::sendDomainServerCheckIn() {
QDataStream packetStream(&domainServerPacket, QIODevice::Append);
// pack our data to send to the domain-server
- packetStream << _ownerType << _publicSockAddr << _localSockAddr << (quint8) _nodeTypesOfInterest.size();
+ packetStream << _ownerType << _publicSockAddr << _localSockAddr << _nodeTypesOfInterest.toList();
- // copy over the bytes for node types of interest, if required
- foreach (NodeType_t nodeTypeOfInterest, _nodeTypesOfInterest) {
- packetStream << nodeTypeOfInterest;
+
+ // if this is a connect request, and we can present a username signature, send it along
+ if (!_domainHandler.isConnected()) {
+ DataServerAccountInfo& accountInfo = AccountManager::getInstance().getAccountInfo();
+ packetStream << accountInfo.getUsername();
+
+ const QByteArray& usernameSignature = AccountManager::getInstance().getAccountInfo().getUsernameSignature();
+
+ if (!usernameSignature.isEmpty()) {
+ qDebug() << "Including username signature in domain connect request.";
+ packetStream << usernameSignature;
+ } else {
+ qDebug() << "Private key not present - domain connect request cannot include username signature";
+ }
}
if (!isUsingDTLS) {
diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp
index e3bfbb8f84..be4fb68bfb 100644
--- a/libraries/networking/src/PacketHeaders.cpp
+++ b/libraries/networking/src/PacketHeaders.cpp
@@ -114,7 +114,7 @@ QString nameForPacketType(PacketType type) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainListRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeRequestAssignment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeCreateAssignment);
- PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainOAuthRequest);
+ PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectionDenied);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMuteEnvironment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioStreamStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDataServerConfirm);
diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h
index 2d298d253d..ab596673f5 100644
--- a/libraries/networking/src/PacketHeaders.h
+++ b/libraries/networking/src/PacketHeaders.h
@@ -38,7 +38,7 @@ enum PacketType {
PacketTypeDomainListRequest,
PacketTypeRequestAssignment,
PacketTypeCreateAssignment,
- PacketTypeDomainOAuthRequest,
+ PacketTypeDomainConnectionDenied,
PacketTypeMuteEnvironment,
PacketTypeAudioStreamStats,
PacketTypeDataServerConfirm,
@@ -81,7 +81,7 @@ typedef char PacketVersion;
const QSet NON_VERIFIED_PACKETS = QSet()
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
- << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainOAuthRequest
+ << PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainConnectionDenied
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse
<< PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery << PacketTypeEntityQuery
<< PacketTypeOctreeDataNack << PacketTypeVoxelEditNack << PacketTypeParticleEditNack << PacketTypeEntityEditNack
diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp
new file mode 100644
index 0000000000..5b53a84dc4
--- /dev/null
+++ b/libraries/networking/src/RSAKeypairGenerator.cpp
@@ -0,0 +1,91 @@
+//
+// RSAKeypairGenerator.cpp
+// libraries/networking/src
+//
+// Created by Stephen Birarda on 2014-10-14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include
+#include
+#include
+
+#include
+
+#include "RSAKeypairGenerator.h"
+
+RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) :
+ QObject(parent)
+{
+
+}
+
+void RSAKeypairGenerator::generateKeypair() {
+
+ RSA* keyPair = RSA_new();
+ BIGNUM* exponent = BN_new();
+
+ const unsigned long RSA_KEY_EXPONENT = 65537;
+ BN_set_word(exponent, RSA_KEY_EXPONENT);
+
+ // seed the random number generator before we call RSA_generate_key_ex
+ srand(time(NULL));
+
+ const int RSA_KEY_BITS = 2048;
+
+ if (!RSA_generate_key_ex(keyPair, RSA_KEY_BITS, exponent, NULL)) {
+ qDebug() << "Error generating 2048-bit RSA Keypair -" << ERR_get_error();
+
+ emit errorGeneratingKeypair();
+
+ // we're going to bust out of here but first we cleanup the BIGNUM
+ BN_free(exponent);
+ return;
+ }
+
+ // we don't need the BIGNUM anymore so clean that up
+ BN_free(exponent);
+
+ // grab the public key and private key from the file
+ unsigned char* publicKeyDER = NULL;
+ int publicKeyLength = i2d_RSAPublicKey(keyPair, &publicKeyDER);
+
+ unsigned char* privateKeyDER = NULL;
+ int privateKeyLength = i2d_RSAPrivateKey(keyPair, &privateKeyDER);
+
+ if (publicKeyLength <= 0 || privateKeyLength <= 0) {
+ qDebug() << "Error getting DER public or private key from RSA struct -" << ERR_get_error();
+
+ emit errorGeneratingKeypair();
+
+ // cleanup the RSA struct
+ RSA_free(keyPair);
+
+ // cleanup the public and private key DER data, if required
+ if (publicKeyLength > 0) {
+ delete publicKeyDER;
+ }
+
+ if (privateKeyLength > 0) {
+ delete privateKeyDER;
+ }
+
+ return;
+ }
+
+ // we have the public key and private key in memory
+ // we can cleanup the RSA struct before we continue on
+ RSA_free(keyPair);
+
+ QByteArray publicKeyArray(reinterpret_cast(publicKeyDER), publicKeyLength);
+ QByteArray privateKeyArray(reinterpret_cast(privateKeyDER), privateKeyLength);
+
+ // cleanup the publicKeyDER and publicKeyDER data
+ delete publicKeyDER;
+ delete privateKeyDER;
+
+ emit generatedKeypair(publicKeyArray, privateKeyArray);
+}
\ No newline at end of file
diff --git a/libraries/networking/src/RSAKeypairGenerator.h b/libraries/networking/src/RSAKeypairGenerator.h
new file mode 100644
index 0000000000..dd90313625
--- /dev/null
+++ b/libraries/networking/src/RSAKeypairGenerator.h
@@ -0,0 +1,28 @@
+//
+// RSAKeypairGenerator.h
+// libraries/networking/src
+//
+// Created by Stephen Birarda on 2014-10-14.
+// Copyright 2014 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#ifndef hifi_RSAKeypairGenerator_h
+#define hifi_RSAKeypairGenerator_h
+
+#include
+
+class RSAKeypairGenerator : public QObject {
+ Q_OBJECT
+public:
+ RSAKeypairGenerator(QObject* parent = 0);
+public slots:
+ void generateKeypair();
+signals:
+ void errorGeneratingKeypair();
+ void generatedKeypair(const QByteArray& publicKey, const QByteArray& privateKey);
+};
+
+#endif // hifi_RSAKeypairGenerator_h
\ No newline at end of file
diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp
index 549f02ae3c..4fc6905e3a 100644
--- a/libraries/networking/src/UserActivityLogger.cpp
+++ b/libraries/networking/src/UserActivityLogger.cpp
@@ -69,7 +69,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
multipart);
}
-void UserActivityLogger::requestFinished(const QJsonObject& object) {
+void UserActivityLogger::requestFinished(QNetworkReply& requestReply) {
// qDebug() << object;
}
diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h
index 1bd966d632..9b100461ee 100644
--- a/libraries/networking/src/UserActivityLogger.h
+++ b/libraries/networking/src/UserActivityLogger.h
@@ -39,7 +39,7 @@ public slots:
void wentTo(QString destinationType, QString destinationName);
private slots:
- void requestFinished(const QJsonObject& object);
+ void requestFinished(QNetworkReply& requestReply);
void requestError(QNetworkReply& errorReply);
private: