From b6b73af2b487b10e9cabe85299f498ef0b683df2 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Jun 2016 14:27:45 -0700 Subject: [PATCH 1/8] Clean up domain-server setup --- domain-server/src/DomainServer.cpp | 70 +++++++++++++----------------- domain-server/src/DomainServer.h | 2 +- 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 223cab61da..a4b57226ed 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -104,23 +104,25 @@ DomainServer::DomainServer(int argc, char* argv[]) : connect(&_settingsManager, &DomainServerSettingsManager::updateNodePermissions, &_gatekeeper, &DomainGatekeeper::updateNodePermissions); - if (optionallyReadX509KeyAndCertificate() && optionallySetupOAuth()) { - // we either read a certificate and private key or were not passed one - // and completed login or did not need to - - qDebug() << "Setting up LimitedNodeList and assignments."; - setupNodeListAndAssignments(); - - // setup automatic networking settings with data server - setupAutomaticNetworking(); - - // preload some user public keys so they can connect on first request - _gatekeeper.preloadAllowedUserPublicKeys(); - - optionallyGetTemporaryName(args); + // if we were given a certificate/private key or oauth credentials they must succeed + if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) { + return; } + qDebug() << "Setting up domain-server"; + setupNodeListAndAssignments(); + setupAutomaticNetworking(); + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request + _metadata = new DomainMetadata(this); + + // check for the temporary name parameter + const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; + if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { + getTemporaryName(); + } + + qDebug() << "domain-server" << nullptr << "is running"; } DomainServer::~DomainServer() { @@ -233,34 +235,25 @@ bool DomainServer::optionallySetupOAuth() { static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id"; -void DomainServer::optionallyGetTemporaryName(const QStringList& arguments) { - // check for the temporary name parameter - const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; +void DomainServer::getTemporaryName(bool force) { + // check if we already have a domain ID + const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); - if (arguments.contains(GET_TEMPORARY_NAME_SWITCH)) { - - // make sure we don't already have a domain ID - const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); - if (idValueVariant) { - qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings." - << "Will not request temporary name."; + if (idValueVariant) { + qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."; + if (force) { + qWarning() << "Temporary domain name will be requested to replace it."; + } else { + qWarning() << "Temporary domain name will not be requested."; return; } - - // we've been asked to grab a temporary name from the API - // so fire off that request now - auto accountManager = DependencyManager::get(); - - // get callbacks for temporary domain result - JSONCallbackParameters callbackParameters; - callbackParameters.jsonCallbackReceiver = this; - callbackParameters.jsonCallbackMethod = "handleTempDomainSuccess"; - callbackParameters.errorCallbackReceiver = this; - callbackParameters.errorCallbackMethod = "handleTempDomainError"; - - accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, - QNetworkAccessManager::PostOperation, callbackParameters); } + + // request a temporary name from the metaverse + auto accountManager = DependencyManager::get(); + JSONCallbackParameters callbackParameters { this, "handleTempDomainSuccess", this, "handleTempDomainError" }; + accountManager->sendRequest("/api/v1/domains/temporary", AccountManagerAuth::None, + QNetworkAccessManager::PostOperation, callbackParameters); } void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { @@ -333,7 +326,6 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { - const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index c742dbc9b3..8a25591605 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -100,7 +100,7 @@ private: bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); - void optionallyGetTemporaryName(const QStringList& arguments); + void getTemporaryName(bool force = false); static bool packetVersionMatch(const udt::Packet& packet); From 3a36b0a2e5307094c106c73d4ddfb3cb5a289838 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Jun 2016 18:31:23 -0700 Subject: [PATCH 2/8] add temporary domain info to account info --- libraries/networking/src/AccountManager.cpp | 5 +++++ libraries/networking/src/AccountManager.h | 3 +++ libraries/networking/src/DataServerAccountInfo.cpp | 13 ++++++++++--- libraries/networking/src/DataServerAccountInfo.h | 8 +++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 26b3801ec1..ac6d0cd4a0 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -471,6 +471,11 @@ void AccountManager::setAccessTokenForCurrentAuthURL(const QString& accessToken) persistAccountToFile(); } +void AccountManager::setTemporaryDomain(const QUuid& domainID, const QString& key) { + _accountInfo.setTemporaryDomain(domainID, key); + persistAccountToFile(); +} + void AccountManager::requestAccessToken(const QString& login, const QString& password) { QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 4803d2625f..dc3315eb45 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -88,6 +88,9 @@ public: void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; } + void setTemporaryDomain(const QUuid& domainID, const QString& key); + const QString& getTemporaryDomainKey(const QUuid& domainID) { return _accountInfo.getTemporaryDomainKey(domainID); } + public slots: void requestAccessToken(const QString& login, const QString& password); diff --git a/libraries/networking/src/DataServerAccountInfo.cpp b/libraries/networking/src/DataServerAccountInfo.cpp index 211bfdccfa..6c6f3eb90c 100644 --- a/libraries/networking/src/DataServerAccountInfo.cpp +++ b/libraries/networking/src/DataServerAccountInfo.cpp @@ -25,6 +25,8 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif +const QString DataServerAccountInfo::EMPTY_KEY = QString(); + DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherInfo) : QObject() { _accessToken = otherInfo._accessToken; _username = otherInfo._username; @@ -33,6 +35,8 @@ DataServerAccountInfo::DataServerAccountInfo(const DataServerAccountInfo& otherI _walletID = otherInfo._walletID; _privateKey = otherInfo._privateKey; _domainID = otherInfo._domainID; + _temporaryDomainID = otherInfo._temporaryDomainID; + _temporaryDomainApiKey = otherInfo._temporaryDomainApiKey; } DataServerAccountInfo& DataServerAccountInfo::operator=(const DataServerAccountInfo& otherInfo) { @@ -51,6 +55,8 @@ void DataServerAccountInfo::swap(DataServerAccountInfo& otherInfo) { swap(_walletID, otherInfo._walletID); swap(_privateKey, otherInfo._privateKey); swap(_domainID, otherInfo._domainID); + swap(_temporaryDomainID, otherInfo._temporaryDomainID); + swap(_temporaryDomainApiKey, otherInfo._temporaryDomainApiKey); } void DataServerAccountInfo::setAccessTokenFromJSON(const QJsonObject& jsonObject) { @@ -145,13 +151,14 @@ QByteArray DataServerAccountInfo::signPlaintext(const QByteArray& plaintext) { QDataStream& operator<<(QDataStream &out, const DataServerAccountInfo& info) { out << info._accessToken << info._username << info._xmppPassword << info._discourseApiKey - << info._walletID << info._privateKey << info._domainID; - + << info._walletID << info._privateKey << info._domainID + << info._temporaryDomainID << info._temporaryDomainApiKey; return out; } QDataStream& operator>>(QDataStream &in, DataServerAccountInfo& info) { in >> info._accessToken >> info._username >> info._xmppPassword >> info._discourseApiKey - >> info._walletID >> info._privateKey >> info._domainID; + >> info._walletID >> info._privateKey >> info._domainID + >> info._temporaryDomainID >> info._temporaryDomainApiKey; return in; } diff --git a/libraries/networking/src/DataServerAccountInfo.h b/libraries/networking/src/DataServerAccountInfo.h index 6ee726efde..8cb416cf34 100644 --- a/libraries/networking/src/DataServerAccountInfo.h +++ b/libraries/networking/src/DataServerAccountInfo.h @@ -22,6 +22,7 @@ const float SATOSHIS_PER_CREDIT = 100000000.0f; class DataServerAccountInfo : public QObject { Q_OBJECT + const static QString EMPTY_KEY; public: DataServerAccountInfo() {}; DataServerAccountInfo(const DataServerAccountInfo& otherInfo); @@ -52,6 +53,9 @@ public: void setDomainID(const QUuid& domainID) { _domainID = domainID; } const QUuid& getDomainID() const { return _domainID; } + void setTemporaryDomain(const QUuid& domainID, const QString& key) { _temporaryDomainID = domainID; _temporaryDomainApiKey = key; } + const QString& getTemporaryDomainKey(const QUuid& domainID) { return domainID == _temporaryDomainID ? _temporaryDomainApiKey : EMPTY_KEY; } + bool hasProfile() const; void setProfileInfoFromJSON(const QJsonObject& jsonObject); @@ -67,7 +71,9 @@ private: QString _xmppPassword; QString _discourseApiKey; QUuid _walletID; - QUuid _domainID; // if this holds account info for a domain, this holds the ID of that domain + QUuid _domainID; + QUuid _temporaryDomainID; + QString _temporaryDomainApiKey; QByteArray _privateKey; }; From eebf8e91c6bdcca2308e64b75a4b8ee97b1b970b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Jun 2016 19:02:27 -0700 Subject: [PATCH 3/8] add api_key to domains/public_key updates --- libraries/networking/src/AccountManager.cpp | 27 +++++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index ac6d0cd4a0..38f33da6ce 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -652,22 +652,33 @@ void AccountManager::processGeneratedKeypair() { const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; QString uploadPath; - if (keypairGenerator->getDomainID().isNull()) { + const auto& domainID = keypairGenerator->getDomainID(); + if (domainID.isNull()) { uploadPath = USER_PUBLIC_KEY_UPDATE_PATH; } else { - uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(keypairGenerator->getDomainID())); + uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID)); } // 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(keypairGenerator->getPublicKey()); + QHttpPart publicKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - requestMultiPart->append(keyPart); + publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); + publicKeyPart.setBody(keypairGenerator->getPublicKey()); + requestMultiPart->append(publicKeyPart); + + if (!domainID.isNull()) { + const auto& key = getTemporaryDomainKey(domainID); + QHttpPart apiKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"api_key\"")); + apiKeyPart.setBody(key.toUtf8()); + requestMultiPart->append(apiKeyPart); + } // setup callback parameters so we know once the keypair upload has succeeded or failed JSONCallbackParameters callbackParameters; From a6115cba6e981f17477edd98a0b6695770cc5c19 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Jun 2016 19:04:03 -0700 Subject: [PATCH 4/8] update temporary domains to use api_key --- domain-server/src/DomainServer.cpp | 149 +++++++++++++++++++---------- domain-server/src/DomainServer.h | 10 +- 2 files changed, 105 insertions(+), 54 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index a4b57226ed..df1697af28 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -76,6 +76,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationVersion(BuildInfo::VERSION); QSettings::setDefaultFormat(QSettings::IniFormat); + qDebug() << "Setting up domain-server"; + // make sure we have a fresh AccountManager instance // (need this since domain-server can restart itself and maintain static variables) DependencyManager::set(); @@ -109,20 +111,26 @@ DomainServer::DomainServer(int argc, char* argv[]) : return; } - qDebug() << "Setting up domain-server"; - setupNodeListAndAssignments(); - setupAutomaticNetworking(); - _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request - - _metadata = new DomainMetadata(this); - // check for the temporary name parameter const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { getTemporaryName(); } - qDebug() << "domain-server" << nullptr << "is running"; + setupNodeListAndAssignments(); + setupAutomaticNetworking(); + if (!getID().isNull()) { + setupHeartbeatToMetaverse(); + // send the first heartbeat immediately + sendHeartbeatToMetaverse(); + } + + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request + + _metadata = new DomainMetadata(this); + + + qDebug() << "domain-server is running"; } DomainServer::~DomainServer() { @@ -150,6 +158,10 @@ void DomainServer::restart() { exit(DomainServer::EXIT_CODE_REBOOT); } +const QUuid& DomainServer::getID() { + return DependencyManager::get()->getSessionUUID(); +} + bool DomainServer::optionallyReadX509KeyAndCertificate() { const QString X509_CERTIFICATE_OPTION = "cert"; const QString X509_PRIVATE_KEY_OPTION = "key"; @@ -264,11 +276,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { static const QString DOMAIN_KEY = "domain"; static const QString ID_KEY = "id"; static const QString NAME_KEY = "name"; + static const QString KEY_KEY = "api_key"; auto domainObject = jsonObject[DATA_KEY].toObject()[DOMAIN_KEY].toObject(); if (!domainObject.isEmpty()) { auto id = domainObject[ID_KEY].toString(); auto name = domainObject[NAME_KEY].toString(); + auto key = domainObject[KEY_KEY].toString(); qInfo() << "Received new temporary domain name" << name; qDebug() << "The temporary domain ID is" << id; @@ -284,9 +298,13 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) { // change our domain ID immediately DependencyManager::get()->setSessionUUID(QUuid { id }); - // change our automatic networking settings so that we're communicating with the ICE server - setupICEHeartbeatForFullNetworking(); + // store the new token to the account info + auto accountManager = DependencyManager::get(); + accountManager->setTemporaryDomain(id, key); + // update our heartbeats to use the correct id + setupICEHeartbeatForFullNetworking(); + setupHeartbeatToMetaverse(); } else { qWarning() << "There were problems parsing the API response containing a temporary domain name. Please try again" << "via domain-server relaunch or from the domain-server settings."; @@ -325,7 +343,7 @@ bool DomainServer::packetVersionMatch(const udt::Packet& packet) { } -void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { +void DomainServer::setupNodeListAndAssignments() { const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port"; QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION); @@ -450,29 +468,20 @@ bool DomainServer::resetAccountManagerAccessToken() { } void DomainServer::setupAutomaticNetworking() { - auto nodeList = DependencyManager::get(); - + qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString(); + auto nodeList = DependencyManager::get(); + const QUuid& domainID = getID(); + if (_automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { setupICEHeartbeatForFullNetworking(); } - _hasAccessToken = resetAccountManagerAccessToken(); - - if (!_hasAccessToken) { - qDebug() << "Will not send heartbeat to Metaverse API without an access token."; - qDebug() << "If this is not a temporary domain add an access token to your config file or via the web interface."; - - return; - } - if (_automaticNetworkingSetting == IP_ONLY_AUTOMATIC_NETWORKING_VALUE || _automaticNetworkingSetting == FULL_AUTOMATIC_NETWORKING_VALUE) { - const QUuid& domainID = nodeList->getSessionUUID(); - if (!domainID.isNull()) { qDebug() << "domain-server" << _automaticNetworkingSetting << "automatic networking enabled for ID" << uuidStringWithoutCurlyBraces(domainID) << "via" << _oauthProviderURL.toString(); @@ -484,9 +493,6 @@ void DomainServer::setupAutomaticNetworking() { // have the LNL enable public socket updating via STUN nodeList->startSTUNPublicSocketUpdate(); - } else { - // send our heartbeat to data server so it knows what our network settings are - sendHeartbeatToMetaverse(); } } else { qDebug() << "Cannot enable domain-server automatic networking without a domain ID." @@ -494,18 +500,20 @@ void DomainServer::setupAutomaticNetworking() { return; } - } else { - sendHeartbeatToMetaverse(); } +} - qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; - - // no matter the auto networking settings we should heartbeat to the data-server every 15s +void DomainServer::setupHeartbeatToMetaverse() { + // heartbeat to the data-server every 15s const int DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS = 15 * 1000; - QTimer* dataHeartbeatTimer = new QTimer(this); - connect(dataHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse())); - dataHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); + if (!_metaverseHeartbeatTimer) { + // setup a timer to heartbeat with the metaverse-server + _metaverseHeartbeatTimer = new QTimer { this }; + connect(_metaverseHeartbeatTimer, SIGNAL(timeout()), this, SLOT(sendHeartbeatToMetaverse())); + // do not send a heartbeat immediately - this avoids flooding if the heartbeat fails with a 401 + _metaverseHeartbeatTimer->start(DOMAIN_SERVER_DATA_WEB_HEARTBEAT_MSECS); + } } void DomainServer::setupICEHeartbeatForFullNetworking() { @@ -524,22 +532,21 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { limitedNodeList->startSTUNPublicSocketUpdate(); // to send ICE heartbeats we'd better have a private key locally with an uploaded public key - auto accountManager = DependencyManager::get(); - auto domainID = accountManager->getAccountInfo().getDomainID(); - // if we have an access token and we don't have a private key or the current domain ID has changed // we should generate a new keypair - if (!accountManager->getAccountInfo().hasPrivateKey() || domainID != limitedNodeList->getSessionUUID()) { - accountManager->generateNewDomainKeypair(limitedNodeList->getSessionUUID()); + auto accountManager = DependencyManager::get(); + if (!accountManager->getAccountInfo().hasPrivateKey() || accountManager->getAccountInfo().getDomainID() != getID()) { + accountManager->generateNewDomainKeypair(getID()); } // hookup to the signal from account manager that tells us when keypair is available connect(accountManager.data(), &AccountManager::newKeypair, this, &DomainServer::handleKeypairChange); if (!_iceHeartbeatTimer) { - // setup a timer to heartbeat with the ice-server every so often + // setup a timer to heartbeat with the ice-server _iceHeartbeatTimer = new QTimer { this }; connect(_iceHeartbeatTimer, &QTimer::timeout, this, &DomainServer::sendHeartbeatToIceServer); + sendHeartbeatToIceServer(); _iceHeartbeatTimer->start(ICE_HEARBEAT_INTERVAL_MSECS); } } @@ -1067,9 +1074,6 @@ void DomainServer::performIPAddressUpdate(const HifiSockAddr& newPublicSockAddr) } void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { - auto nodeList = DependencyManager::get(); - const QUuid& domainID = nodeList->getSessionUUID(); - // Setup the domain object to send to the data server QJsonObject domainObject; @@ -1088,6 +1092,13 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous); domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain; + const auto& temporaryDomainKey = DependencyManager::get()->getTemporaryDomainKey(getID()); + if (!temporaryDomainKey.isEmpty()) { + // add the temporary domain token + const QString KEY_KEY = "api_key"; + domainObject[KEY_KEY] = temporaryDomainKey; + } + if (_metadata) { // Add the metadata to the heartbeat static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat"; @@ -1097,18 +1108,47 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) { QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact))); static const QString DOMAIN_UPDATE = "/api/v1/domains/%1"; - DependencyManager::get()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), - AccountManagerAuth::Required, + DependencyManager::get()->sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())), + AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), + JSONCallbackParameters(nullptr, QString(), this, "handleMetaverseHeartbeatError"), domainUpdateJSON.toUtf8()); } +void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) { + if (!_metaverseHeartbeatTimer) { + // avoid rehandling errors from the same issue + return; + } + + // if we have a temporary domain with a bad token, we will get a 401 + if (requestReply.error() == QNetworkReply::NetworkError::AuthenticationRequiredError) { + static const QString DATA_KEY = "data"; + static const QString TOKEN_KEY = "api_key"; + + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; + + if (!tokenFailure.isNull()) { + qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; + + // halt heartbeats until we have a token + _metaverseHeartbeatTimer->deleteLater(); + _metaverseHeartbeatTimer = nullptr; + + // give up eventually to avoid flooding traffic + static const int MAX_ATTEMPTS = 5; + static int attempt = 0; + if (++attempt < MAX_ATTEMPTS) { + // get a new temporary name and token + getTemporaryName(true); + } + } + } +} + void DomainServer::sendICEServerAddressToMetaverseAPI() { if (!_iceServerSocket.isNull()) { - auto nodeList = DependencyManager::get(); - const QUuid& domainID = nodeList->getSessionUUID(); - const QString ICE_SERVER_ADDRESS = "ice_server_address"; QJsonObject domainObject; @@ -1116,6 +1156,13 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() { // we're using full automatic networking and we have a current ice-server socket, use that now domainObject[ICE_SERVER_ADDRESS] = _iceServerSocket.getAddress().toString(); + const auto& temporaryDomainKey = DependencyManager::get()->getTemporaryDomainKey(getID()); + if (!temporaryDomainKey.isEmpty()) { + // add the temporary domain token + const QString KEY_KEY = "api_key"; + domainObject[KEY_KEY] = temporaryDomainKey; + } + QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); // make sure we hear about failure so we can retry @@ -1127,7 +1174,7 @@ void DomainServer::sendICEServerAddressToMetaverseAPI() { static const QString DOMAIN_ICE_ADDRESS_UPDATE = "/api/v1/domains/%1/ice_server_address"; - DependencyManager::get()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), + DependencyManager::get()->sendRequest(DOMAIN_ICE_ADDRESS_UPDATE.arg(uuidStringWithoutCurlyBraces(getID())), AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, callbackParameters, diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index 8a25591605..138cb9ca2d 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -80,6 +80,8 @@ private slots: void handleTempDomainSuccess(QNetworkReply& requestReply); void handleTempDomainError(QNetworkReply& requestReply); + void handleMetaverseHeartbeatError(QNetworkReply& requestReply); + void queuedQuit(QString quitMessage, int exitCode); void handleKeypairChange(); @@ -96,7 +98,9 @@ signals: void userDisconnected(); private: - void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); + const QUuid& getID(); + + void setupNodeListAndAssignments(); bool optionallySetupOAuth(); bool optionallyReadX509KeyAndCertificate(); @@ -108,6 +112,7 @@ private: void setupAutomaticNetworking(); void setupICEHeartbeatForFullNetworking(); + void setupHeartbeatToMetaverse(); void sendHeartbeatToMetaverse(const QString& networkAddress); void randomizeICEServerAddress(bool shouldTriggerHostLookup); @@ -178,6 +183,7 @@ private: // These will be parented to this, they are not dangling DomainMetadata* _metadata { nullptr }; QTimer* _iceHeartbeatTimer { nullptr }; + QTimer* _metaverseHeartbeatTimer { nullptr }; QList _iceServerAddresses; QSet _failedIceServerAddresses; @@ -186,8 +192,6 @@ private: int _numHeartbeatDenials { 0 }; bool _connectedToICEServer { false }; - bool _hasAccessToken { false }; - friend class DomainGatekeeper; friend class DomainMetadata; }; From 4a30d549add061e408c95d692e2098ef6eb70207 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 17 Jun 2016 19:26:22 -0700 Subject: [PATCH 5/8] force temp domain reset on 404 too (401 already) --- domain-server/src/DomainServer.cpp | 51 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index df1697af28..192c0d26e6 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -1121,29 +1121,42 @@ void DomainServer::handleMetaverseHeartbeatError(QNetworkReply& requestReply) { return; } - // if we have a temporary domain with a bad token, we will get a 401 - if (requestReply.error() == QNetworkReply::NetworkError::AuthenticationRequiredError) { - static const QString DATA_KEY = "data"; - static const QString TOKEN_KEY = "api_key"; + // check if we need to force a new temporary domain name + switch (requestReply.error()) { + // if we have a temporary domain with a bad token, we get a 401 + case QNetworkReply::NetworkError::AuthenticationRequiredError: { + static const QString DATA_KEY = "data"; + static const QString TOKEN_KEY = "api_key"; - QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); - auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; + QJsonObject jsonObject = QJsonDocument::fromJson(requestReply.readAll()).object(); + auto tokenFailure = jsonObject[DATA_KEY].toObject()[TOKEN_KEY]; - if (!tokenFailure.isNull()) { - qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; - - // halt heartbeats until we have a token - _metaverseHeartbeatTimer->deleteLater(); - _metaverseHeartbeatTimer = nullptr; - - // give up eventually to avoid flooding traffic - static const int MAX_ATTEMPTS = 5; - static int attempt = 0; - if (++attempt < MAX_ATTEMPTS) { - // get a new temporary name and token - getTemporaryName(true); + if (!tokenFailure.isNull()) { + qWarning() << "Temporary domain name lacks a valid API key, and is being reset."; } + break; } + // if the domain does not (or no longer) exists, we get a 404 + case QNetworkReply::NetworkError::ContentNotFoundError: + qWarning() << "Domain not found, getting a new temporary domain."; + break; + // otherwise, we erred on something else, and should not force a temporary domain + default: + return; + } + + // halt heartbeats until we have a token + _metaverseHeartbeatTimer->deleteLater(); + _metaverseHeartbeatTimer = nullptr; + + // give up eventually to avoid flooding traffic + static const int MAX_ATTEMPTS = 5; + static int attempt = 0; + if (++attempt < MAX_ATTEMPTS) { + // get a new temporary name and token + getTemporaryName(true); + } else { + qWarning() << "Already attempted too many temporary domain requests. Please set a domain ID manually or restart."; } } From 1de1c632afbb4f6f124108d32265e2aa3ec25c53 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 23 Jun 2016 17:16:42 -0700 Subject: [PATCH 6/8] use private_description instead of description for domain settings --- domain-server/resources/web/settings/js/settings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index c2cb2ecb80..4188e86548 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -555,7 +555,7 @@ function createNewDomainID(description, justConnected) { // get the JSON object ready that we'll use to create a new domain var domainJSON = { "domain": { - "description": description + "private_description": description }, "access_token": $(Settings.ACCESS_TOKEN_SELECTOR).val() } @@ -748,8 +748,8 @@ function chooseFromHighFidelityDomains(clickedButton) { _.each(data.data.domains, function(domain){ var domainString = ""; - if (domain.description) { - domainString += '"' + domain.description + '" - '; + if (domain.private_description) { + domainString += '"' + domain.private_description + '" - '; } domainString += domain.id; From 13310923c4440ec6b0a97dbf89627dc63fe832ad Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 23 Jun 2016 19:38:23 -0700 Subject: [PATCH 7/8] reset to temp domain after logout --- .../resources/web/settings/js/settings.js | 2 ++ domain-server/src/DomainServer.cpp | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 4188e86548..4f153d6190 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -457,6 +457,8 @@ function disonnectHighFidelityAccount() { }, function(){ // we need to post to settings to clear the access-token $(Settings.ACCESS_TOKEN_SELECTOR).val('').change(); + // reset the domain id to get a new temporary name + $(Settings.DOMAIN_ID_SELECTOR).val('').change(); saveSettings(); }); } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 192c0d26e6..ca0d7728dd 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -111,12 +111,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : return; } - // check for the temporary name parameter - const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; - if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { - getTemporaryName(); - } - setupNodeListAndAssignments(); setupAutomaticNetworking(); if (!getID().isNull()) { @@ -125,6 +119,12 @@ DomainServer::DomainServer(int argc, char* argv[]) : sendHeartbeatToMetaverse(); } + // check for the temporary name parameter + const QString GET_TEMPORARY_NAME_SWITCH = "--get-temp-name"; + if (args.contains(GET_TEMPORARY_NAME_SWITCH)) { + getTemporaryName(); + } + _gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request _metadata = new DomainMetadata(this); @@ -251,12 +251,13 @@ void DomainServer::getTemporaryName(bool force) { // check if we already have a domain ID const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH); + qInfo() << "Requesting temporary domain name"; if (idValueVariant) { - qWarning() << "Temporary domain name requested but a domain ID is already present in domain-server settings."; + qDebug() << "A domain ID is already present in domain-server settings:" << idValueVariant->toString(); if (force) { - qWarning() << "Temporary domain name will be requested to replace it."; + qDebug() << "Requesting temporary domain name to replace current ID:" << getID(); } else { - qWarning() << "Temporary domain name will not be requested."; + qInfo() << "Abandoning request of temporary domain name."; return; } } From b1b378a91feb062e160cf794002e59c13e5ed11b Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Thu, 23 Jun 2016 19:38:41 -0700 Subject: [PATCH 8/8] add back access token to domain-server --- domain-server/src/DomainServer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index ca0d7728dd..6e5c1fd361 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -470,6 +470,9 @@ bool DomainServer::resetAccountManagerAccessToken() { void DomainServer::setupAutomaticNetworking() { qDebug() << "Updating automatic networking setting in domain-server to" << _automaticNetworkingSetting; + + resetAccountManagerAccessToken(); + _automaticNetworkingSetting = _settingsManager.valueOrDefaultValueForKeyPath(METAVERSE_AUTOMATIC_NETWORKING_KEY_PATH).toString();