summaryrefslogtreecommitdiffstats
path: root/logic/auth
diff options
context:
space:
mode:
Diffstat (limited to 'logic/auth')
-rw-r--r--logic/auth/MojangAccount.cpp36
-rw-r--r--logic/auth/MojangAccount.h55
-rw-r--r--logic/auth/YggdrasilTask.cpp23
-rw-r--r--logic/auth/YggdrasilTask.h22
-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.cpp0
-rw-r--r--logic/auth/flows/InvalidateTask.h0
-rw-r--r--logic/auth/flows/RefreshTask.cpp156
-rw-r--r--logic/auth/flows/RefreshTask.h43
-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:
};
-