diff options
Diffstat (limited to 'logic/auth')
-rw-r--r-- | logic/auth/MojangAccount.cpp | 36 | ||||
-rw-r--r-- | logic/auth/MojangAccount.h | 55 | ||||
-rw-r--r-- | logic/auth/YggdrasilTask.cpp | 23 | ||||
-rw-r--r-- | logic/auth/YggdrasilTask.h | 22 | ||||
-rw-r--r-- | logic/auth/flows/AuthenticateTask.cpp (renamed from logic/auth/AuthenticateTask.cpp) | 88 | ||||
-rw-r--r-- | logic/auth/flows/AuthenticateTask.h (renamed from logic/auth/AuthenticateTask.h) | 12 | ||||
-rw-r--r-- | logic/auth/flows/InvalidateTask.cpp | 0 | ||||
-rw-r--r-- | logic/auth/flows/InvalidateTask.h | 0 | ||||
-rw-r--r-- | logic/auth/flows/RefreshTask.cpp | 156 | ||||
-rw-r--r-- | logic/auth/flows/RefreshTask.h | 43 | ||||
-rw-r--r-- | logic/auth/flows/ValidateTask.cpp (renamed from logic/auth/ValidateTask.cpp) | 8 | ||||
-rw-r--r-- | logic/auth/flows/ValidateTask.h (renamed from logic/auth/ValidateTask.h) | 9 |
12 files changed, 322 insertions, 130 deletions
diff --git a/logic/auth/MojangAccount.cpp b/logic/auth/MojangAccount.cpp index 4f3839bc..4a61cf19 100644 --- a/logic/auth/MojangAccount.cpp +++ b/logic/auth/MojangAccount.cpp @@ -23,8 +23,7 @@ #include <logger/QsLog.h> -MojangAccount::MojangAccount(const QString& username, QObject* parent) : - QObject(parent) +MojangAccount::MojangAccount(const QString &username, QObject *parent) : QObject(parent) { // Generate a client token. m_clientToken = QUuid::createUuid().toString(); @@ -34,9 +33,9 @@ MojangAccount::MojangAccount(const QString& username, QObject* parent) : m_currentProfile = -1; } -MojangAccount::MojangAccount(const QString& username, const QString& clientToken, - const QString& accessToken, QObject* parent) : - QObject(parent) +MojangAccount::MojangAccount(const QString &username, const QString &clientToken, + const QString &accessToken, QObject *parent) + : QObject(parent) { m_username = username; m_clientToken = clientToken; @@ -45,7 +44,7 @@ MojangAccount::MojangAccount(const QString& username, const QString& clientToken m_currentProfile = -1; } -MojangAccount::MojangAccount(const MojangAccount& other, QObject* parent) +MojangAccount::MojangAccount(const MojangAccount &other, QObject *parent) { m_username = other.username(); m_clientToken = other.clientToken(); @@ -55,7 +54,6 @@ MojangAccount::MojangAccount(const MojangAccount& other, QObject* parent) m_currentProfile = other.m_currentProfile; } - QString MojangAccount::username() const { return m_username; @@ -66,18 +64,17 @@ QString MojangAccount::clientToken() const return m_clientToken; } -void MojangAccount::setClientToken(const QString& clientToken) +void MojangAccount::setClientToken(const QString &clientToken) { m_clientToken = clientToken; } - QString MojangAccount::accessToken() const { return m_accessToken; } -void MojangAccount::setAccessToken(const QString& accessToken) +void MojangAccount::setAccessToken(const QString &accessToken) { m_accessToken = accessToken; } @@ -92,7 +89,7 @@ const QList<AccountProfile> MojangAccount::profiles() const return m_profiles; } -const AccountProfile* MojangAccount::currentProfile() const +const AccountProfile *MojangAccount::currentProfile() const { if (m_currentProfile < 0) { @@ -105,9 +102,9 @@ const AccountProfile* MojangAccount::currentProfile() const return &m_profiles.at(m_currentProfile); } -bool MojangAccount::setProfile(const QString& profileId) +bool MojangAccount::setProfile(const QString &profileId) { - const QList<AccountProfile>& profiles = this->profiles(); + const QList<AccountProfile> &profiles = this->profiles(); for (int i = 0; i < profiles.length(); i++) { if (profiles.at(i).id() == profileId) @@ -119,14 +116,14 @@ bool MojangAccount::setProfile(const QString& profileId) return false; } -void MojangAccount::loadProfiles(const ProfileList& profiles) +void MojangAccount::loadProfiles(const ProfileList &profiles) { m_profiles.clear(); for (auto profile : profiles) m_profiles.append(profile); } -MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject& object) +MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object) { // The JSON object must at least have a username for it to be valid. if (!object.value("username").isString()) @@ -134,7 +131,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject& object) QLOG_ERROR() << "Can't load Mojang account info from JSON object. Username field is missing or of the wrong type."; return nullptr; } - + QString username = object.value("username").toString(""); QString clientToken = object.value("clientToken").toString(""); QString accessToken = object.value("accessToken").toString(""); @@ -201,7 +198,7 @@ AccountProfile::AccountProfile(const QString& id, const QString& name) m_name = name; } -AccountProfile::AccountProfile(const AccountProfile& other) +AccountProfile::AccountProfile(const AccountProfile &other) { m_id = other.m_id; m_name = other.m_name; @@ -217,4 +214,7 @@ QString AccountProfile::name() const return m_name; } - +void MojangAccount::propagateChange() +{ + emit changed(); +} diff --git a/logic/auth/MojangAccount.h b/logic/auth/MojangAccount.h index 062b8aa2..25a85790 100644 --- a/logic/auth/MojangAccount.h +++ b/logic/auth/MojangAccount.h @@ -19,6 +19,7 @@ #include <QString> #include <QList> #include <QJsonObject> +#include <QPair> #include <memory> @@ -27,7 +28,6 @@ class MojangAccount; typedef std::shared_ptr<MojangAccount> MojangAccountPtr; Q_DECLARE_METATYPE(MojangAccountPtr) - /** * Class that represents a profile within someone's Mojang account. * @@ -38,56 +38,69 @@ Q_DECLARE_METATYPE(MojangAccountPtr) class AccountProfile { public: - AccountProfile(const QString& id, const QString& name); - AccountProfile(const AccountProfile& other); + AccountProfile(const QString &id, const QString &name); + AccountProfile(const AccountProfile &other); QString id() const; QString name() const; + protected: QString m_id; QString m_name; }; - typedef QList<AccountProfile> ProfileList; +struct User +{ + QString id; + // pair of key:value + // we don't know if the keys:value mapping is 1:1, so a list is used. + QList<QPair<QString, QString>> properties; +}; /** * Object that stores information about a certain Mojang account. * - * Said information may include things such as that account's username, client token, and access + * Said information may include things such as that account's username, client token, and access * token if the user chose to stay logged in. */ class MojangAccount : public QObject { -Q_OBJECT + Q_OBJECT public: /** * Constructs a new MojangAccount with the given username. * The client token will be generated automatically and the access token will be blank. */ - explicit MojangAccount(const QString& username, QObject* parent = 0); + explicit MojangAccount(const QString &username, QObject *parent = 0); /** * Constructs a new MojangAccount with the given username, client token, and access token. */ - explicit MojangAccount(const QString& username, const QString& clientToken, const QString& accessToken, QObject* parent = 0); + explicit MojangAccount(const QString &username, const QString &clientToken, + const QString &accessToken, QObject *parent = 0); /** * Constructs a new MojangAccount matching the given account. */ - MojangAccount(const MojangAccount& other, QObject* parent); + MojangAccount(const MojangAccount &other, QObject *parent); /** * Loads a MojangAccount from the given JSON object. */ - static MojangAccountPtr loadFromJson(const QJsonObject& json); + static MojangAccountPtr loadFromJson(const QJsonObject &json); /** * Saves a MojangAccount to a JSON object and returns it. */ QJsonObject saveToJson(); + /** + * Update the account on disk and lists (it changed, for whatever reason) + * This is called by various Yggdrasil tasks. + */ + void propagateChange(); /** * This MojangAccount's username. May be an email address if the account is migrated. @@ -103,7 +116,7 @@ public: /** * Sets the MojangAccount's client token to the given value. */ - void setClientToken(const QString& token); + void setClientToken(const QString &token); /** * This MojangAccount's access token. @@ -114,7 +127,7 @@ public: /** * Changes this MojangAccount's access token to the given value. */ - void setAccessToken(const QString& token); + void setAccessToken(const QString &token); /** * Get full session ID @@ -130,25 +143,31 @@ public: * Returns a pointer to the currently selected profile. * If no profile is selected, returns the first profile in the profile list or nullptr if there are none. */ - const AccountProfile* currentProfile() const; + const AccountProfile *currentProfile() const; /** * Sets the currently selected profile to the profile with the given ID string. * If profileId is not in the list of available profiles, the function will simply return false. */ - bool setProfile(const QString& profileId); + bool setProfile(const QString &profileId); /** * Clears the current account profile list and replaces it with the given profile list. */ - void loadProfiles(const ProfileList& profiles); + void loadProfiles(const ProfileList &profiles); +signals: + /** + * This isgnal is emitted whrn the account changes + */ + void changed(); protected: QString m_username; QString m_clientToken; - QString m_accessToken; // Blank if not logged in. - int m_currentProfile; // Index of the selected profile within the list of available profiles. -1 if nothing is selected. + QString m_accessToken; // Blank if not logged in. + int m_currentProfile; // Index of the selected profile within the list of available + // profiles. -1 if nothing is selected. ProfileList m_profiles; // List of available profiles. + User m_user; // the user structure, whatever it is. }; - diff --git a/logic/auth/YggdrasilTask.cpp b/logic/auth/YggdrasilTask.cpp index 31c8fbab..797e84cd 100644 --- a/logic/auth/YggdrasilTask.cpp +++ b/logic/auth/YggdrasilTask.cpp @@ -25,13 +25,12 @@ #include <MultiMC.h> #include <logic/auth/MojangAccount.h> -YggdrasilTask::YggdrasilTask(MojangAccountPtr account, QObject* parent) : Task(parent) +YggdrasilTask::YggdrasilTask(MojangAccountPtr account, QObject *parent) : Task(parent) { m_error = nullptr; m_account = account; } - YggdrasilTask::~YggdrasilTask() { if (m_error) @@ -46,17 +45,18 @@ void YggdrasilTask::executeTask() QJsonDocument doc(getRequestContent()); auto worker = MMC->qnam(); - connect(worker.get(), SIGNAL(finished(QNetworkReply*)), this, - SLOT(processReply(QNetworkReply*))); + connect(worker.get(), SIGNAL(finished(QNetworkReply *)), this, + SLOT(processReply(QNetworkReply *))); QUrl reqUrl("https://authserver.mojang.com/" + getEndpoint()); QNetworkRequest netRequest(reqUrl); netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - - m_netReply = worker->post(netRequest, doc.toJson()); + + QByteArray requestData = doc.toJson(); + m_netReply = worker->post(netRequest, requestData); } -void YggdrasilTask::processReply(QNetworkReply* reply) +void YggdrasilTask::processReply(QNetworkReply *reply) { setStatus(getStateMessage(STATE_PROCESSING_RESPONSE)); @@ -76,7 +76,6 @@ void YggdrasilTask::processReply(QNetworkReply* reply) QJsonParseError jsonError; QByteArray replyData = reply->readAll(); QJsonDocument doc = QJsonDocument::fromJson(replyData, &jsonError); - // Check the response code. int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); @@ -85,15 +84,16 @@ void YggdrasilTask::processReply(QNetworkReply* reply) // If the response code was 200, then there shouldn't be an error. Make sure anyways. // Also, sometimes an empty reply indicates success. If there was no data received, // pass an empty json object to the processResponse function. - if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) + if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0) { if (!processResponse(replyData.size() > 0 ? doc.object() : QJsonObject())) { - YggdrasilTask::Error* err = getError(); + YggdrasilTask::Error *err = getError(); if (err) emitFailed(err->getErrorMessage()); else - emitFailed(tr("An unknown error occurred when processing the response from the authentication server.")); + emitFailed(tr("An unknown error occurred when processing the response " + "from the authentication server.")); } else { @@ -166,4 +166,3 @@ MojangAccountPtr YggdrasilTask::getMojangAccount() const { return this->m_account; } - diff --git a/logic/auth/YggdrasilTask.h b/logic/auth/YggdrasilTask.h index 5a433aeb..62638c9d 100644 --- a/logic/auth/YggdrasilTask.h +++ b/logic/auth/YggdrasilTask.h @@ -24,15 +24,14 @@ class QNetworkReply; - /** * A Yggdrasil task is a task that performs an operation on a given mojang account. */ class YggdrasilTask : public Task { -Q_OBJECT + Q_OBJECT public: - explicit YggdrasilTask(MojangAccountPtr account, QObject* parent=0); + explicit YggdrasilTask(MojangAccountPtr account, QObject *parent = 0); ~YggdrasilTask(); /** @@ -49,7 +48,10 @@ public: QString getCause() const { return m_cause; } /// Gets the string to display in the GUI for describing this error. - QString getDisplayMessage() { return getErrorMessage(); } + QString getDisplayMessage() + { + return getErrorMessage(); + } protected: QString m_shortError; @@ -66,7 +68,7 @@ public: * Returns a pointer to a YggdrasilTask::Error object if an error has occurred. * If no error has occurred, returns a null pointer. */ - virtual Error* getError() const; + virtual Error *getError() const; protected: /** @@ -120,11 +122,11 @@ protected: MojangAccountPtr m_account; - QNetworkReply* m_netReply; + QNetworkReply *m_netReply; - Error* m_error; + Error *m_error; -protected slots: - void processReply(QNetworkReply* reply); +protected +slots: + void processReply(QNetworkReply *reply); }; - diff --git a/logic/auth/AuthenticateTask.cpp b/logic/auth/flows/AuthenticateTask.cpp index bf7a54f9..ec2004d6 100644 --- a/logic/auth/AuthenticateTask.cpp +++ b/logic/auth/flows/AuthenticateTask.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <logic/auth/AuthenticateTask.h> +#include <logic/auth/flows/AuthenticateTask.h> #include <logic/auth/MojangAccount.h> @@ -26,8 +26,9 @@ #include "logger/QsLog.h" -AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString& password, QObject* parent) : - YggdrasilTask(account, parent), m_password(password) +AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString &password, + QObject *parent) + : YggdrasilTask(account, parent), m_password(password) { } @@ -37,20 +38,22 @@ QJsonObject AuthenticateTask::getRequestContent() const * { * "agent": { // optional * "name": "Minecraft", // So far this is the only encountered value - * "version": 1 // This number might be increased + * "version": 1 // This number might be increased * // by the vanilla client in the future * }, * "username": "mojang account name", // Can be an email address or player name for // unmigrated accounts * "password": "mojang account password", * "clientToken": "client identifier" // optional + * "requestUser": true/false // request the user structure * } */ QJsonObject req; { QJsonObject agent; - // C++ makes string literals void* for some stupid reason, so we have to tell it QString... Thanks Obama. + // C++ makes string literals void* for some stupid reason, so we have to tell it + // QString... Thanks Obama. agent.insert("name", QString("Minecraft")); agent.insert("version", 1); req.insert("agent", agent); @@ -58,6 +61,7 @@ QJsonObject AuthenticateTask::getRequestContent() const req.insert("username", getMojangAccount()->username()); req.insert("password", m_password); + req.insert("requestUser", true); // If we already have a client token, give it to the server. // Otherwise, let the server give us one. @@ -69,10 +73,12 @@ QJsonObject AuthenticateTask::getRequestContent() const bool AuthenticateTask::processResponse(QJsonObject responseData) { - // Read the response data. We need to get the client token, access token, and the selected profile. + // Read the response data. We need to get the client token, access token, and the selected + // profile. QLOG_DEBUG() << "Processing authentication response."; - - // If we already have a client token, make sure the one the server gave us matches our existing one. + + // If we already have a client token, make sure the one the server gave us matches our + // existing one. QLOG_DEBUG() << "Getting client token."; QString clientToken = responseData.value("clientToken").toString(""); if (clientToken.isEmpty()) @@ -82,16 +88,17 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) QLOG_ERROR() << "Server didn't send a client token."; return false; } - if (!getMojangAccount()->clientToken().isEmpty() && clientToken != getMojangAccount()->clientToken()) + if (!getMojangAccount()->clientToken().isEmpty() && + clientToken != getMojangAccount()->clientToken()) { - // The server changed our client token! Obey its wishes, but complain. That's what I do for my parents, so... - QLOG_WARN() << "Server changed our client token to '" << clientToken + // The server changed our client token! Obey its wishes, but complain. That's what I do + // for my parents, so... + QLOG_WARN() << "Server changed our client token to '" << clientToken << "'. This shouldn't happen, but it isn't really a big deal."; } // Set the client token. getMojangAccount()->setClientToken(clientToken); - // Now, we set the access token. QLOG_DEBUG() << "Getting access token."; QString accessToken = responseData.value("accessToken").toString(""); @@ -104,10 +111,9 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) // Set the access token. getMojangAccount()->setAccessToken(accessToken); - // Now we load the list of available profiles. - // Mojang hasn't yet implemented the profile system, - // but we might as well support what's there so we + // Mojang hasn't yet implemented the profile system, + // but we might as well support what's there so we // don't have trouble implementing it later. QLOG_DEBUG() << "Loading profile list."; QJsonArray availableProfiles = responseData.value("availableProfiles").toArray(); @@ -121,10 +127,11 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) if (id.isEmpty() || name.isEmpty()) { - // This should never happen, but we might as well + // This should never happen, but we might as well // warn about it if it does so we can debug it easily. // You never know when Mojang might do something truly derpy. - QLOG_WARN() << "Found entry in available profiles list with missing ID or name field. Ignoring it."; + QLOG_WARN() << "Found entry in available profiles list with missing ID or name " + "field. Ignoring it."; } // Now, add a new AccountProfile entry to the list. @@ -133,10 +140,8 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) // Put the list of profiles we loaded into the MojangAccount object. getMojangAccount()->loadProfiles(loadedProfiles); - - // Finally, we set the current profile to the correct value. This is pretty simple. - // We do need to make sure that the current profile that the server gave us + // We do need to make sure that the current profile that the server gave us // is actually in the available profiles list. // If it isn't, we'll just fail horribly (*shouldn't* ever happen, but you never know). QLOG_DEBUG() << "Setting current profile."; @@ -151,51 +156,23 @@ bool AuthenticateTask::processResponse(QJsonObject responseData) if (!getMojangAccount()->setProfile(currentProfileId)) { // TODO: Set an error to display to the user. - QLOG_ERROR() << "Server specified a selected profile that wasn't in the available profiles list."; + QLOG_ERROR() << "Server specified a selected profile that wasn't in the available " + "profiles list."; return false; } - /* -public class User -{ - private String id; - private List<Property> properties; - - public String getId() - { - return this.id; - } - - public List<Property> getProperties() { - return this.properties; - } - public class Property { - private String name; - private String value; - - public Property() { } - public String getKey() { return this.name; } - - public String getValue() - { - return this.value; - } - } -} -*/ - // this is what the vanilla launcher passes to the userProperties launch param // doesn't seem to be used for anything so far? I don't get any of this data on my account // (peterixxx) // is it a good idea to log this? - if(responseData.contains("user")) + if (responseData.contains("user")) { auto obj = responseData.value("user").toObject(); auto userId = obj.value("id").toString(); auto propArray = obj.value("properties").toArray(); QLOG_DEBUG() << "User ID: " << userId; QLOG_DEBUG() << "User Properties: "; - for(auto prop: propArray) + for (auto prop : propArray) { auto propTuple = prop.toObject(); auto name = propTuple.value("name").toString(); @@ -203,8 +180,9 @@ public class User QLOG_DEBUG() << name << " : " << value; } } - - // We've made it through the minefield of possible errors. Return true to indicate that we've succeeded. + + // We've made it through the minefield of possible errors. Return true to indicate that + // we've succeeded. QLOG_DEBUG() << "Finished reading authentication response."; return true; } @@ -226,5 +204,3 @@ QString AuthenticateTask::getStateMessage(const YggdrasilTask::State state) cons return YggdrasilTask::getStateMessage(state); } } - - diff --git a/logic/auth/AuthenticateTask.h b/logic/auth/flows/AuthenticateTask.h index 54a6b79a..3b99caad 100644 --- a/logic/auth/AuthenticateTask.h +++ b/logic/auth/flows/AuthenticateTask.h @@ -22,25 +22,25 @@ #include <QJsonObject> /** - * The authenticate task takes a MojangAccount with no access token and password and attempts to authenticate with Mojang's servers. + * The authenticate task takes a MojangAccount with no access token and password and attempts to + * authenticate with Mojang's servers. * If successful, it will set the MojangAccount's access token. */ class AuthenticateTask : public YggdrasilTask { -Q_OBJECT + Q_OBJECT public: - AuthenticateTask(MojangAccountPtr account, const QString& password, QObject* parent=0); + AuthenticateTask(MojangAccountPtr account, const QString &password, QObject *parent = 0); protected: virtual QJsonObject getRequestContent() const; - + virtual QString getEndpoint() const; virtual bool processResponse(QJsonObject responseData); - + QString getStateMessage(const YggdrasilTask::State state) const; private: QString m_password; }; - diff --git a/logic/auth/flows/InvalidateTask.cpp b/logic/auth/flows/InvalidateTask.cpp new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/logic/auth/flows/InvalidateTask.cpp diff --git a/logic/auth/flows/InvalidateTask.h b/logic/auth/flows/InvalidateTask.h new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/logic/auth/flows/InvalidateTask.h diff --git a/logic/auth/flows/RefreshTask.cpp b/logic/auth/flows/RefreshTask.cpp new file mode 100644 index 00000000..b56ed9bc --- /dev/null +++ b/logic/auth/flows/RefreshTask.cpp @@ -0,0 +1,156 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <logic/auth/flows/RefreshTask.h> + +#include <logic/auth/MojangAccount.h> + +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonArray> +#include <QVariant> +#include <QDebug> + +#include "logger/QsLog.h" + +RefreshTask::RefreshTask(MojangAccountPtr account, QObject *parent) + : YggdrasilTask(account, parent) +{ +} + +QJsonObject RefreshTask::getRequestContent() const +{ + /* + * { + * "clientToken": "client identifier" + * "accessToken": "current access token to be refreshed" + * "selectedProfile": // specifying this causes errors + * { + * "id": "profile ID" + * "name": "profile name" + * } + * "requestUser": true/false // request the user structure + * } + */ + auto account = getMojangAccount(); + QJsonObject req; + req.insert("clientToken", account->clientToken()); + req.insert("accessToken", account->accessToken()); + /* + { + auto currentProfile = account->currentProfile(); + QJsonObject profile; + profile.insert("id", currentProfile->id()); + profile.insert("name", currentProfile->name()); + req.insert("selectedProfile", profile); + } + */ + req.insert("requestUser", true); + + return req; +} + +bool RefreshTask::processResponse(QJsonObject responseData) +{ + auto account = getMojangAccount(); + + // Read the response data. We need to get the client token, access token, and the selected + // profile. + QLOG_DEBUG() << "Processing authentication response."; + + // If we already have a client token, make sure the one the server gave us matches our + // existing one. + QString clientToken = responseData.value("clientToken").toString(""); + if (clientToken.isEmpty()) + { + // Fail if the server gave us an empty client token + // TODO: Set an error properly to display to the user. + QLOG_ERROR() << "Server didn't send a client token."; + return false; + } + if (!account->clientToken().isEmpty() && clientToken != account->clientToken()) + { + // The server changed our client token! Obey its wishes, but complain. That's what I do + // for my parents, so... + QLOG_ERROR() << "Server changed our client token to '" << clientToken + << "'. This shouldn't happen, but it isn't really a big deal."; + return false; + } + + // Now, we set the access token. + QLOG_DEBUG() << "Getting new access token."; + QString accessToken = responseData.value("accessToken").toString(""); + if (accessToken.isEmpty()) + { + // Fail if the server didn't give us an access token. + // TODO: Set an error properly to display to the user. + QLOG_ERROR() << "Server didn't send an access token."; + return false; + } + + // we validate that the server responded right. (our current profile = returned current + // profile) + QJsonObject currentProfile = responseData.value("selectedProfile").toObject(); + QString currentProfileId = currentProfile.value("id").toString(""); + if (account->currentProfile()->id() != currentProfileId) + { + // TODO: Set an error to display to the user. + QLOG_ERROR() << "Server didn't specify the same selected profile as ours."; + return false; + } + + // this is what the vanilla launcher passes to the userProperties launch param + if (responseData.contains("user")) + { + auto obj = responseData.value("user").toObject(); + auto userId = obj.value("id").toString(); + auto propArray = obj.value("properties").toArray(); + QLOG_DEBUG() << "User ID: " << userId; + QLOG_DEBUG() << "User Properties: "; + for (auto prop : propArray) + { + auto propTuple = prop.toObject(); + auto name = propTuple.value("name").toString(); + auto value = propTuple.value("value").toString(); + QLOG_DEBUG() << name << " : " << value; + } + } + + // We've made it through the minefield of possible errors. Return true to indicate that + // we've succeeded. + QLOG_DEBUG() << "Finished reading refresh response."; + // Reset the access token. + account->setAccessToken(accessToken); + account->propagateChange(); + return true; +} + +QString RefreshTask::getEndpoint() const +{ + return "refresh"; +} + +QString RefreshTask::getStateMessage(const YggdrasilTask::State state) const +{ + switch (state) + { + case STATE_SENDING_REQUEST: + return tr("Refreshing: Sending request."); + case STATE_PROCESSING_RESPONSE: + return tr("Refreshing: Processing response."); + default: + return YggdrasilTask::getStateMessage(state); + } +} diff --git a/logic/auth/flows/RefreshTask.h b/logic/auth/flows/RefreshTask.h new file mode 100644 index 00000000..2596f6c7 --- /dev/null +++ b/logic/auth/flows/RefreshTask.h @@ -0,0 +1,43 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <logic/auth/YggdrasilTask.h> + +#include <QObject> +#include <QString> +#include <QJsonObject> + +/** + * The authenticate task takes a MojangAccount with a possibly timed-out access token + * and attempts to authenticate with Mojang's servers. + * If successful, it will set the new access token. The token is considered validated. + */ +class RefreshTask : public YggdrasilTask +{ + Q_OBJECT +public: + RefreshTask(MojangAccountPtr account, QObject *parent = 0); + +protected: + virtual QJsonObject getRequestContent() const; + + virtual QString getEndpoint() const; + + virtual bool processResponse(QJsonObject responseData); + + QString getStateMessage(const YggdrasilTask::State state) const; +}; diff --git a/logic/auth/ValidateTask.cpp b/logic/auth/flows/ValidateTask.cpp index 994d24e4..d9e0e46b 100644 --- a/logic/auth/ValidateTask.cpp +++ b/logic/auth/flows/ValidateTask.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <logic/auth/ValidateTask.h> +#include <logic/auth/flows/ValidateTask.h> #include <logic/auth/MojangAccount.h> @@ -26,8 +26,8 @@ #include "logger/QsLog.h" -ValidateTask::ValidateTask(MojangAccountPtr account, QObject* parent) : - YggdrasilTask(account, parent) +ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent) + : YggdrasilTask(account, parent) { } @@ -62,5 +62,3 @@ QString ValidateTask::getStateMessage(const YggdrasilTask::State state) const return YggdrasilTask::getStateMessage(state); } } - - diff --git a/logic/auth/ValidateTask.h b/logic/auth/flows/ValidateTask.h index 5bbc69c7..3ff78c6a 100644 --- a/logic/auth/ValidateTask.h +++ b/logic/auth/flows/ValidateTask.h @@ -26,19 +26,18 @@ */ class ValidateTask : public YggdrasilTask { -Q_OBJECT + Q_OBJECT public: - ValidateTask(MojangAccountPtr account, QObject* parent=0); + ValidateTask(MojangAccountPtr account, QObject *parent = 0); protected: virtual QJsonObject getRequestContent() const; - + virtual QString getEndpoint() const; virtual bool processResponse(QJsonObject responseData); - + QString getStateMessage(const YggdrasilTask::State state) const; private: }; - |