From 6cab831ea039e3f050cf8023c0856b6bc809caf8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 23 Feb 2016 14:48:31 -0800 Subject: [PATCH] re-gen the interface keypair while being denied from domain --- interface/src/Application.cpp | 23 ------------ interface/src/Application.h | 4 --- .../scripting/WindowScriptingInterface.cpp | 2 +- libraries/networking/src/AccountManager.cpp | 24 ++----------- libraries/networking/src/AccountManager.h | 3 +- libraries/networking/src/DomainHandler.cpp | 35 +++++++++++++++++++ libraries/networking/src/DomainHandler.h | 7 ++++ libraries/networking/src/NodeList.cpp | 11 +++--- 8 files changed, 55 insertions(+), 54 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ee95c189e9..aeec71980a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -926,9 +926,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : SpacemouseManager::getInstance().init(); #endif - auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::DomainConnectionDenied, this, "handleDomainConnectionDeniedPacket"); - // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, @@ -3961,30 +3958,10 @@ void Application::clearDomainOctreeDetails() { void Application::domainChanged(const QString& domainHostname) { updateWindowTitle(); clearDomainOctreeDetails(); - _domainConnectionRefusals.clear(); // disable physics until we have enough information about our new location to not cause craziness. _physicsEnabled = false; } -void Application::handleDomainConnectionDeniedPacket(QSharedPointer message) { - // Read deny reason from packet - quint16 reasonSize; - message->readPrimitive(&reasonSize); - QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); - - // 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 - qCDebug(interfaceapp) << "The domain-server denied a connection request: " << reason; - qCDebug(interfaceapp) << "You may need to re-log to generate a keypair so you can provide a username signature."; - - if (!_domainConnectionRefusals.contains(reason)) { - _domainConnectionRefusals.append(reason); - emit domainConnectionRefused(reason); - } - - AccountManager::getInstance().checkAndSignalForAccessToken(); -} - void Application::connectedToDomain(const QString& hostname) { AccountManager& accountManager = AccountManager::getInstance(); const QUuid& domainID = DependencyManager::get()->getDomainHandler().getUUID(); diff --git a/interface/src/Application.h b/interface/src/Application.h index d5b677302a..3ac70ea6f7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -223,7 +223,6 @@ signals: void svoImportRequested(const QString& url); void checkBackgroundDownloads(); - void domainConnectionRefused(const QString& reason); void fullAvatarURLChanged(const QString& newValue, const QString& modelName); @@ -291,8 +290,6 @@ private slots: void activeChanged(Qt::ApplicationState state); void domainSettingsReceived(const QJsonObject& domainSettingsObject); - void handleDomainConnectionDeniedPacket(QSharedPointer message); - void notifyPacketVersionMismatch(); void loadSettings(); @@ -472,7 +469,6 @@ private: typedef bool (Application::* AcceptURLMethod)(const QString &); static const QHash _acceptedExtensions; - QList _domainConnectionRefusals; glm::uvec2 _renderResolution; int _maxOctreePPS = DEFAULT_MAX_OCTREE_PPS; diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 3e8d0d0360..1726708efb 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -25,7 +25,7 @@ WindowScriptingInterface::WindowScriptingInterface() { const DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); connect(&domainHandler, &DomainHandler::connectedToDomain, this, &WindowScriptingInterface::domainChanged); - connect(qApp, &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); + connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); connect(qApp, &Application::svoImportRequested, [this](const QString& urlString) { static const QMetaMethod svoImportRequestedSignal = diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 877f858e97..e8fc5d743b 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -83,20 +83,6 @@ AccountManager::AccountManager() : connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); } -void AccountManager::setIsAgent(bool isAgent) { - if (_isAgent != isAgent) { - _isAgent = isAgent; - - if (_isAgent) { - // any profile changes in account manager should generate a new keypair - connect(this, &AccountManager::profileChanged, this, &AccountManager::generateNewUserKeypair); - } else { - // disconnect the generation of a new keypair during profile changes - disconnect(this, &AccountManager::profileChanged, this, &AccountManager::generateNewUserKeypair); - } - } -} - const QString DOUBLE_SLASH_SUBSTITUTE = "slashslash"; void AccountManager::logout() { @@ -203,13 +189,9 @@ void AccountManager::setAuthURL(const QUrl& authURL) { } } - if (_isAgent && !_accountInfo.getAccessToken().token.isEmpty()) { - // profile info isn't guaranteed to be saved too - if (_accountInfo.hasProfile()) { - emit profileChanged(); - } else { - requestProfile(); - } + if (_isAgent && !_accountInfo.getAccessToken().token.isEmpty() && !_accountInfo.hasProfile()) { + // we are missing profile information, request it now + requestProfile(); } // tell listeners that the auth endpoint has changed diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index fc8157e8d8..0ebefafbed 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -62,7 +62,7 @@ public: QHttpMultiPart* dataMultiPart = NULL, const QVariantMap& propertyMap = QVariantMap()); - void setIsAgent(bool isAgent); + void setIsAgent(bool isAgent) { _isAgent = isAgent; } const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -121,6 +121,7 @@ private: void passErrorToCallback(QNetworkReply* reply); QUrl _authURL; + QMap _pendingCallbackMap; DataServerAccountInfo _accountInfo; diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index db775983e1..ff0bbf31e0 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -92,6 +92,8 @@ void DomainHandler::softReset() { disconnect(); clearSettings(); + + _connectionDenialsSinceKeypairRegen = 0; // cancel the failure timeout for any pending requests for settings QMetaObject::invokeMethod(&_settingsTimer, "stop"); @@ -105,6 +107,7 @@ void DomainHandler::hardReset() { _iceServerSockAddr = HifiSockAddr(); _hostname = QString(); _sockAddr.clear(); + _hasCheckedForAccessToken = false; // clear any pending path we may have wanted to ask the previous DS about _pendingPath.clear(); @@ -347,3 +350,35 @@ void DomainHandler::processICEResponsePacket(QSharedPointer mes emit icePeerSocketsReceived(); } } + +void DomainHandler::processDomainServerConnectionDeniedPacket(QSharedPointer message) { + // Read deny reason from packet + quint16 reasonSize; + message->readPrimitive(&reasonSize); + QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); + + // 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 + qCWarning(networking) << "The domain-server denied a connection request: " << reason; + qCWarning(networking) << "Make sure you are logged in."; + + if (!_domainConnectionRefusals.contains(reason)) { + _domainConnectionRefusals.append(reason); + emit domainConnectionRefused(reason); + } + + auto& accountManager = AccountManager::getInstance(); + + if (_hasCheckedForAccessToken) { + accountManager.checkAndSignalForAccessToken(); + _hasCheckedForAccessToken = true; + } + + static const int CONNECTION_DENIALS_FOR_KEYPAIR_REGEN = 3; + + // force a re-generation of key-pair after CONNECTION_DENIALS_FOR_KEYPAIR_REGEN failed connection attempts + if (++_connectionDenialsSinceKeypairRegen >= CONNECTION_DENIALS_FOR_KEYPAIR_REGEN) { + accountManager.generateNewUserKeypair(); + _connectionDenialsSinceKeypairRegen = 0; + } +} diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index f60ac2fbe6..b245305a93 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -92,6 +92,7 @@ public slots: void processICEPingReplyPacket(QSharedPointer message); void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); void processICEResponsePacket(QSharedPointer icePacket); + void processDomainServerConnectionDeniedPacket(QSharedPointer message); private slots: void completedHostnameLookup(const QHostInfo& hostInfo); @@ -113,6 +114,8 @@ signals: void settingsReceived(const QJsonObject& domainSettingsObject); void settingsReceiveFail(); + void domainConnectionRefused(QString reason); + private: void sendDisconnectPacket(); void hardReset(); @@ -130,6 +133,10 @@ private: QJsonObject _settingsObject; QString _pendingPath; QTimer _settingsTimer; + + QStringList _domainConnectionRefusals; + bool _hasCheckedForAccessToken { false }; + int _connectionDenialsSinceKeypairRegen { 0 }; }; #endif // hifi_DomainHandler_h diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 37ff79c454..23451897b0 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -80,11 +80,16 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned // send a ping punch immediately connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer); + auto &accountManager = AccountManager::getInstance(); + + // assume that we may need to send a new DS check in anytime a new keypair is generated + connect(&accountManager, &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn); + // clear out NodeList when login is finished - connect(&AccountManager::getInstance(), &AccountManager::loginComplete , this, &NodeList::reset); + connect(&accountManager, &AccountManager::loginComplete , this, &NodeList::reset); // clear our NodeList when logout is requested - connect(&AccountManager::getInstance(), &AccountManager::logoutComplete , this, &NodeList::reset); + connect(&accountManager, &AccountManager::logoutComplete , this, &NodeList::reset); // anytime we get a new node we will want to attempt to punch to it connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch); @@ -281,8 +286,6 @@ void NodeList::sendDomainServerCheckIn() { << "but no keypair is present. Waiting for keypair generation to complete."; accountManager.generateNewUserKeypair(); - connect(&accountManager, &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn); - // don't send the check in packet - wait for the keypair first return; }