Offline mode support, part 1

Refactor MojangAccount so it exposes a less generic interface and supports login. Hide the ugly details.
Yggdrasil tasks are now only used from MojangAccount.
This commit is contained in:
Petr Mrázek 2013-12-05 02:39:52 +01:00
parent 613699b362
commit f028aa76bc
18 changed files with 265 additions and 322 deletions

View File

@ -69,10 +69,6 @@
#include "logic/lists/IconList.h"
#include "logic/lists/JavaVersionList.h"
#include "logic/auth/flows/AuthenticateTask.h"
#include "logic/auth/flows/RefreshTask.h"
#include "logic/auth/flows/ValidateTask.h"
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
#include "logic/MinecraftProcess.h"
@ -210,9 +206,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
for(AccountProfile profile : account->profiles())
{
auto meta = MMC->metacache()->resolveEntry("skins", profile.name() + ".png");
auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png");
auto action = CacheDownload::make(
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name() + ".png"),
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name + ".png"),
meta);
job->addNetAction(action);
meta->stale = true;
@ -310,9 +306,9 @@ void MainWindow::repopulateAccountsMenu()
section->setEnabled(false);
accountMenu->addAction(section);
for (AccountProfile profile : account->profiles())
for (auto profile : account->profiles())
{
QAction *action = new QAction(profile.name(), this);
QAction *action = new QAction(profile.name, this);
action->setData(account->username());
action->setCheckable(true);
if(active_username == account->username())
@ -320,7 +316,7 @@ void MainWindow::repopulateAccountsMenu()
action->setChecked(true);
}
action->setIcon(SkinUtils::getFaceFromCache(profile.name()));
action->setIcon(SkinUtils::getFaceFromCache(profile.name));
accountMenu->addAction(action);
connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
}
@ -378,7 +374,7 @@ void MainWindow::activeAccountChanged()
const AccountProfile *profile = account->currentProfile();
if (profile != nullptr)
{
accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->name()));
accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->name));
return;
}
}
@ -790,6 +786,7 @@ void MainWindow::doLaunch()
void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
{
// We'll need to validate the access token to make sure the account is still logged in.
/*
ProgressDialog progDialog(this);
RefreshTask refreshtask(account, &progDialog);
progDialog.exec(&refreshtask);
@ -829,10 +826,12 @@ void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
QMessageBox::Warning, QMessageBox::Ok)->exec();
}
}
*/
}
bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMsg)
{
/*
EditAccountDialog passDialog(errorMsg, this, EditAccountDialog::PasswordField);
if (passDialog.exec() == QDialog::Accepted)
{
@ -848,7 +847,8 @@ bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMs
return doRefreshToken(account, authTask.failReason());
}
}
else return false;
else return false;*/
return false;
}
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)

View File

@ -20,7 +20,6 @@
#include <logger/QsLog.h>
#include <logic/auth/flows/AuthenticateTask.h>
#include <logic/net/NetJob.h>
#include <gui/dialogs/EditAccountDialog.h>
@ -117,8 +116,8 @@ void AccountListDialog::addAccount(const QString& errMsg)
QString username(loginDialog.username());
QString password(loginDialog.password());
MojangAccountPtr account = MojangAccountPtr(new MojangAccount(username));
MojangAccountPtr account = MojangAccount::createFromUsername(username);
/*
ProgressDialog progDialog(this);
AuthenticateTask authTask(account, password, &progDialog);
if (progDialog.exec(&authTask))
@ -132,9 +131,9 @@ void AccountListDialog::addAccount(const QString& errMsg)
for(AccountProfile profile : account->profiles())
{
auto meta = MMC->metacache()->resolveEntry("skins", profile.name() + ".png");
auto meta = MMC->metacache()->resolveEntry("skins", profile.name + ".png");
auto action = CacheDownload::make(
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name() + ".png"),
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name + ".png"),
meta);
job->addNetAction(action);
meta->stale = true;
@ -142,5 +141,6 @@ void AccountListDialog::addAccount(const QString& errMsg)
job->start();
}
*/
}
}

View File

@ -20,8 +20,6 @@
#include <logger/QsLog.h>
#include <logic/auth/flows/AuthenticateTask.h>
#include <gui/dialogs/ProgressDialog.h>
#include <MultiMC.h>

View File

@ -105,7 +105,7 @@ MinecraftProcess *LegacyInstance::prepareForLaunch(MojangAccountPtr account)
#endif
args << "-jar" << LAUNCHER_FILE;
args << account->currentProfile()->name();
args << account->currentProfile()->name;
args << account->sessionId();
args << windowTitle;
args << windowSize;

View File

@ -75,20 +75,22 @@ QString MinecraftProcess::censorPrivateInfo(QString in)
{
if(!m_account)
return in;
else
QString sessionId = m_account->sessionId();
QString accessToken = m_account->accessToken();
QString clientToken = m_account->clientToken();
in.replace(sessionId, "<SESSION ID>");
in.replace(accessToken, "<ACCESS TOKEN>");
in.replace(clientToken, "<CLIENT TOKEN>");
auto profile = m_account->currentProfile();
if(profile)
{
QString sessionId = m_account->sessionId();
QString accessToken = m_account->accessToken();
QString clientToken = m_account->clientToken();
QString profileId = m_account->currentProfile()->id();
QString profileName = m_account->currentProfile()->name();
in.replace(sessionId, "<SESSION ID>");
in.replace(accessToken, "<ACCESS TOKEN>");
in.replace(clientToken, "<CLIENT TOKEN>");
QString profileId = profile->id;
QString profileName = profile->name;
in.replace(profileId, "<PROFILE ID>");
in.replace(profileName, "<PROFILE NAME>");
return in;
}
return in;
}
// console window

View File

@ -77,8 +77,8 @@ QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account)
token_mapping["auth_username"] = account->username();
token_mapping["auth_session"] = account->sessionId();
token_mapping["auth_access_token"] = account->accessToken();
token_mapping["auth_player_name"] = account->currentProfile()->name();
token_mapping["auth_uuid"] = account->currentProfile()->id();
token_mapping["auth_player_name"] = account->currentProfile()->name;
token_mapping["auth_uuid"] = account->currentProfile()->id;
// this is for offline?:
/*

View File

@ -16,113 +16,16 @@
*/
#include "MojangAccount.h"
#include "flows/RefreshTask.h"
#include "flows/AuthenticateTask.h"
#include <QUuid>
#include <QJsonObject>
#include <QJsonArray>
#include <QRegExp>
#include <logger/QsLog.h>
MojangAccount::MojangAccount(const QString &username, QObject *parent) : QObject(parent)
{
// Generate a client token.
m_clientToken = QUuid::createUuid().toString();
m_username = username;
m_currentProfile = -1;
}
MojangAccount::MojangAccount(const QString &username, const QString &clientToken,
const QString &accessToken, QObject *parent)
: QObject(parent)
{
m_username = username;
m_clientToken = clientToken;
m_accessToken = accessToken;
m_currentProfile = -1;
}
MojangAccount::MojangAccount(const MojangAccount &other, QObject *parent)
{
m_username = other.username();
m_clientToken = other.clientToken();
m_accessToken = other.accessToken();
m_profiles = other.m_profiles;
m_currentProfile = other.m_currentProfile;
}
QString MojangAccount::username() const
{
return m_username;
}
QString MojangAccount::clientToken() const
{
return m_clientToken;
}
void MojangAccount::setClientToken(const QString &clientToken)
{
m_clientToken = clientToken;
}
QString MojangAccount::accessToken() const
{
return m_accessToken;
}
void MojangAccount::setAccessToken(const QString &accessToken)
{
m_accessToken = accessToken;
}
QString MojangAccount::sessionId() const
{
return "token:" + m_accessToken + ":" + currentProfile()->id();
}
const QList<AccountProfile> MojangAccount::profiles() const
{
return m_profiles;
}
const AccountProfile *MojangAccount::currentProfile() const
{
if (m_currentProfile < 0)
{
if (m_profiles.length() > 0)
return &m_profiles.at(0);
else
return nullptr;
}
else
return &m_profiles.at(m_currentProfile);
}
bool MojangAccount::setProfile(const QString &profileId)
{
const QList<AccountProfile> &profiles = this->profiles();
for (int i = 0; i < profiles.length(); i++)
{
if (profiles.at(i).id() == profileId)
{
m_currentProfile = i;
return true;
}
}
return false;
}
void MojangAccount::loadProfiles(const ProfileList &profiles)
{
m_profiles.clear();
for (auto profile : profiles)
m_profiles.append(profile);
}
MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
{
// The JSON object must at least have a username for it to be valid.
@ -143,7 +46,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
return nullptr;
}
ProfileList profiles;
QList<AccountProfile> profiles;
for (QJsonValue profileVal : profileArray)
{
QJsonObject profileObject = profileVal.toObject();
@ -154,67 +57,112 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
QLOG_WARN() << "Unable to load a profile because it was missing an ID or a name.";
continue;
}
profiles.append(AccountProfile(id, name));
profiles.append({id, name});
}
MojangAccountPtr account(new MojangAccount(username, clientToken, accessToken));
account->loadProfiles(profiles);
MojangAccountPtr account(new MojangAccount());
account->m_username = username;
account->m_clientToken = clientToken;
account->m_accessToken = accessToken;
account->m_profiles = profiles;
// Get the currently selected profile.
QString currentProfile = object.value("activeProfile").toString("");
if (!currentProfile.isEmpty())
account->setProfile(currentProfile);
account->setCurrentProfile(currentProfile);
return account;
}
QJsonObject MojangAccount::saveToJson()
MojangAccountPtr MojangAccount::createFromUsername(const QString& username)
{
MojangAccountPtr account(new MojangAccount());
account->m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
account->m_username = username;
return account;
}
QJsonObject MojangAccount::saveToJson() const
{
QJsonObject json;
json.insert("username", username());
json.insert("clientToken", clientToken());
json.insert("accessToken", accessToken());
json.insert("username", m_username);
json.insert("clientToken", m_clientToken);
json.insert("accessToken", m_accessToken);
QJsonArray profileArray;
for (AccountProfile profile : m_profiles)
{
QJsonObject profileObj;
profileObj.insert("id", profile.id());
profileObj.insert("name", profile.name());
profileObj.insert("id", profile.id);
profileObj.insert("name", profile.name);
profileArray.append(profileObj);
}
json.insert("profiles", profileArray);
if (currentProfile() != nullptr)
json.insert("activeProfile", currentProfile()->id());
if (m_currentProfile != -1)
json.insert("activeProfile", currentProfile()->id);
return json;
}
AccountProfile::AccountProfile(const QString& id, const QString& name)
bool MojangAccount::setCurrentProfile(const QString &profileId)
{
m_id = id;
m_name = name;
for (int i = 0; i < m_profiles.length(); i++)
{
if (m_profiles[i].id == profileId)
{
m_currentProfile = i;
return true;
}
}
return false;
}
AccountProfile::AccountProfile(const AccountProfile &other)
const AccountProfile* MojangAccount::currentProfile() const
{
m_id = other.m_id;
m_name = other.m_name;
if(m_currentProfile == -1)
return nullptr;
return &m_profiles[m_currentProfile];
}
QString AccountProfile::id() const
AccountStatus MojangAccount::accountStatus() const
{
return m_id;
if(m_accessToken.isEmpty())
return NotVerified;
if(!m_online)
return Verified;
return Online;
}
QString AccountProfile::name() const
bool MojangAccount::login(QString password)
{
return m_name;
if(m_currentTask)
return false;
if(password.isEmpty())
{
m_currentTask.reset(new RefreshTask(this, this));
}
else
{
m_currentTask.reset(new AuthenticateTask(this, password, this));
}
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
m_currentTask->start();
return true;
}
void MojangAccount::propagateChange()
void MojangAccount::authSucceeded()
{
m_online = true;
m_currentTask.reset();
emit changed();
}
void MojangAccount::authFailed(QString reason)
{
m_online = false;
m_accessToken = QString();
m_currentTask.reset();
emit changed();
}

View File

@ -23,34 +23,25 @@
#include <memory>
class YggdrasilTask;
class MojangAccount;
typedef std::shared_ptr<MojangAccount> MojangAccountPtr;
Q_DECLARE_METATYPE(MojangAccountPtr)
/**
* Class that represents a profile within someone's Mojang account.
* A profile within someone's Mojang account.
*
* Currently, the profile system has not been implemented by Mojang yet,
* but we might as well add some things for it in MultiMC right now so
* we don't have to rip the code to pieces to add it later.
*/
class AccountProfile
struct AccountProfile
{
public:
AccountProfile(const QString &id, const QString &name);
AccountProfile(const AccountProfile &other);
QString id() const;
QString name() const;
protected:
QString m_id;
QString m_name;
QString id;
QString name;
};
typedef QList<AccountProfile> ProfileList;
struct User
{
QString id;
@ -59,6 +50,13 @@ struct User
QList<QPair<QString, QString>> properties;
};
enum AccountStatus
{
NotVerified,
Verified,
Online
};
/**
* Object that stores information about a certain Mojang account.
*
@ -68,106 +66,112 @@ struct User
class MojangAccount : public QObject
{
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);
public: /* construction */
//! Do not copy accounts. ever.
explicit MojangAccount(const MojangAccount &other, QObject *parent) = delete;
/**
* 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);
//! Default constructor
explicit MojangAccount(QObject *parent = 0) : QObject(parent) {};
/**
* Constructs a new MojangAccount matching the given account.
*/
MojangAccount(const MojangAccount &other, QObject *parent);
//! Creates an empty account for the specified user name.
static MojangAccountPtr createFromUsername(const QString &username);
/**
* Loads a MojangAccount from the given JSON object.
*/
//! Loads a MojangAccount from the given JSON object.
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.
*/
QString username() const;
/**
* This MojangAccount's client token. This is a UUID used by Mojang's auth servers to identify this client.
* This is unique for each MojangAccount.
*/
QString clientToken() const;
/**
* Sets the MojangAccount's client token to the given value.
*/
void setClientToken(const QString &token);
/**
* This MojangAccount's access token.
* If the user has not chosen to stay logged in, this will be an empty string.
*/
QString accessToken() const;
/**
* Changes this MojangAccount's access token to the given value.
*/
void setAccessToken(const QString &token);
/**
* Get full session ID
*/
QString sessionId() const;
/**
* Returns a list of the available account profiles.
*/
const ProfileList profiles() const;
/**
* 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;
//! Saves a MojangAccount to a JSON object and returns it.
QJsonObject saveToJson() const;
public: /* manipulation */
/**
* 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.
* If profileId is not in the list of available profiles, the function will simply return
* false.
*/
bool setProfile(const QString &profileId);
bool setCurrentProfile(const QString &profileId);
/**
* Clears the current account profile list and replaces it with the given profile list.
* Attempt to login. Empty password means we use the token.
* If the attempt fails because we already are performing some task, it returns false.
*/
void loadProfiles(const ProfileList &profiles);
bool login(QString password = QString());
public: /* queries */
const QString &username() const
{
return m_username;
}
const QString &clientToken() const
{
return m_clientToken;
}
const QString &accessToken() const
{
return m_accessToken;
}
const QList<AccountProfile> &profiles() const
{
return m_profiles;
}
//! Get the session ID required for legacy Minecraft versions
QString sessionId() const
{
if (m_currentProfile != -1 && !m_accessToken.isEmpty())
return "token:" + m_accessToken + ":" + m_profiles[m_currentProfile].id;
return "-";
}
//! Returns the currently selected profile (if none, returns nullptr)
const AccountProfile *currentProfile() const;
//! Returns whether the account is NotVerified, Verified or Online
AccountStatus accountStatus() const;
signals:
/**
* This isgnal is emitted whrn the account changes
* This signal is emitted when the account changes
*/
void changed();
protected:
// TODO: better signalling for the various possible state changes - especially errors
protected: /* variables */
QString m_username;
// Used to identify the client - the user can have multiple clients for the same account
// Think: different launchers, all connecting to the same account/profile
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.
ProfileList m_profiles; // List of available profiles.
User m_user; // the user structure, whatever it is.
// Blank if not logged in.
QString m_accessToken;
// Index of the selected profile within the list of available
// profiles. -1 if nothing is selected.
int m_currentProfile = -1;
// List of available profiles.
QList<AccountProfile> m_profiles;
// the user structure, whatever it is.
User m_user;
// true when the account is verified
bool m_online = false;
// current task we are executing here
std::shared_ptr<YggdrasilTask> m_currentTask;
private slots:
void authSucceeded();
void authFailed(QString reason);
public:
friend class YggdrasilTask;
friend class AuthenticateTask;
friend class ValidateTask;
friend class RefreshTask;
};

View File

@ -25,10 +25,9 @@
#include <MultiMC.h>
#include <logic/auth/MojangAccount.h>
YggdrasilTask::YggdrasilTask(MojangAccountPtr account, QObject *parent) : Task(parent)
YggdrasilTask::YggdrasilTask(MojangAccount *account, QObject *parent)
: Task(parent), m_account(account)
{
m_error = nullptr;
m_account = account;
}
YggdrasilTask::~YggdrasilTask()
@ -81,8 +80,9 @@ void YggdrasilTask::processReply(QNetworkReply *reply)
if (responseCode == 200)
{
// 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,
// 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)
{
@ -102,25 +102,34 @@ void YggdrasilTask::processReply(QNetworkReply *reply)
}
else
{
emitFailed(tr("Failed to parse Yggdrasil JSON response: %1 at offset %2.").arg(jsonError.errorString()).arg(jsonError.offset));
emitFailed(tr("Failed to parse Yggdrasil JSON response: %1 at offset %2.")
.arg(jsonError.errorString())
.arg(jsonError.offset));
}
}
else
{
// If the response code was not 200, then Yggdrasil may have given us information about the error.
// If we can parse the response, then get information from it. Otherwise just say there was an unknown error.
// If the response code was not 200, then Yggdrasil may have given us information
// about the error.
// If we can parse the response, then get information from it. Otherwise just say
// there was an unknown error.
if (jsonError.error == QJsonParseError::NoError)
{
// We were able to parse the server's response. Woo!
// Call processError. If a subclass has overridden it then they'll handle their stuff there.
QLOG_DEBUG() << "The request failed, but the server gave us an error message. Processing error.";
// Call processError. If a subclass has overridden it then they'll handle their
// stuff there.
QLOG_DEBUG() << "The request failed, but the server gave us an error message. "
"Processing error.";
emitFailed(processError(doc.object()));
}
else
{
// The server didn't say anything regarding the error. Give the user an unknown error.
QLOG_DEBUG() << "The request failed and the server gave no error message. Unknown error.";
emitFailed(tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(reply->errorString()));
// The server didn't say anything regarding the error. Give the user an unknown
// error.
QLOG_DEBUG() << "The request failed and the server gave no error message. "
"Unknown error.";
emitFailed(tr("An unknown error occurred when trying to communicate with the "
"authentication server: %1").arg(reply->errorString()));
}
}
}
@ -161,8 +170,3 @@ YggdrasilTask::Error *YggdrasilTask::getError() const
{
return this->m_error;
}
MojangAccountPtr YggdrasilTask::getMojangAccount() const
{
return this->m_account;
}

View File

@ -31,7 +31,7 @@ class YggdrasilTask : public Task
{
Q_OBJECT
public:
explicit YggdrasilTask(MojangAccountPtr account, QObject *parent = 0);
explicit YggdrasilTask(MojangAccount * account, QObject *parent = 0);
~YggdrasilTask();
/**
@ -59,11 +59,6 @@ public:
QString m_cause;
};
/**
* Gets the Mojang account that this task is operating on.
*/
virtual MojangAccountPtr getMojangAccount() const;
/**
* Returns a pointer to a YggdrasilTask::Error object if an error has occurred.
* If no error has occurred, returns a null pointer.
@ -120,11 +115,11 @@ protected:
*/
virtual QString getStateMessage(const State state) const;
MojangAccountPtr m_account;
MojangAccount *m_account = nullptr;
QNetworkReply *m_netReply;
Error *m_error;
Error *m_error = nullptr;
protected
slots:

View File

@ -26,7 +26,7 @@
#include "logger/QsLog.h"
AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString &password,
AuthenticateTask::AuthenticateTask(MojangAccount * account, const QString &password,
QObject *parent)
: YggdrasilTask(account, parent), m_password(password)
{
@ -59,14 +59,14 @@ QJsonObject AuthenticateTask::getRequestContent() const
req.insert("agent", agent);
}
req.insert("username", getMojangAccount()->username());
req.insert("username", m_account->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.
if (!getMojangAccount()->clientToken().isEmpty())
req.insert("clientToken", getMojangAccount()->clientToken());
if (!m_account->m_clientToken.isEmpty())
req.insert("clientToken", m_account->m_clientToken);
return req;
}
@ -88,8 +88,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
QLOG_ERROR() << "Server didn't send a client token.";
return false;
}
if (!getMojangAccount()->clientToken().isEmpty() &&
clientToken != getMojangAccount()->clientToken())
if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken)
{
// The server changed our client token! Obey its wishes, but complain. That's what I do
// for my parents, so...
@ -97,7 +96,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
<< "'. This shouldn't happen, but it isn't really a big deal.";
}
// Set the client token.
getMojangAccount()->setClientToken(clientToken);
m_account->m_clientToken = clientToken;
// Now, we set the access token.
QLOG_DEBUG() << "Getting access token.";
@ -109,7 +108,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
QLOG_ERROR() << "Server didn't send an access token.";
}
// Set the access token.
getMojangAccount()->setAccessToken(accessToken);
m_account->m_accessToken = accessToken;
// Now we load the list of available profiles.
// Mojang hasn't yet implemented the profile system,
@ -117,7 +116,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
// don't have trouble implementing it later.
QLOG_DEBUG() << "Loading profile list.";
QJsonArray availableProfiles = responseData.value("availableProfiles").toArray();
ProfileList loadedProfiles;
QList<AccountProfile> loadedProfiles;
for (auto iter : availableProfiles)
{
QJsonObject profile = iter.toObject();
@ -135,10 +134,10 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
}
// Now, add a new AccountProfile entry to the list.
loadedProfiles.append(AccountProfile(id, name));
loadedProfiles.append({id, name});
}
// Put the list of profiles we loaded into the MojangAccount object.
getMojangAccount()->loadProfiles(loadedProfiles);
m_account->m_profiles = 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
@ -153,7 +152,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
QLOG_ERROR() << "Server didn't specify a currently selected profile.";
return false;
}
if (!getMojangAccount()->setProfile(currentProfileId))
if (!m_account->setCurrentProfile(currentProfileId))
{
// TODO: Set an error to display to the user.
QLOG_ERROR() << "Server specified a selected profile that wasn't in the available "

View File

@ -30,7 +30,7 @@ class AuthenticateTask : public YggdrasilTask
{
Q_OBJECT
public:
AuthenticateTask(MojangAccountPtr account, const QString &password, QObject *parent = 0);
AuthenticateTask(MojangAccount *account, const QString &password, QObject *parent = 0);
protected:
virtual QJsonObject getRequestContent() const;

View File

@ -25,7 +25,7 @@
#include "logger/QsLog.h"
RefreshTask::RefreshTask(MojangAccountPtr account, QObject *parent)
RefreshTask::RefreshTask(MojangAccount *account, QObject *parent)
: YggdrasilTask(account, parent)
{
}
@ -44,13 +44,12 @@ QJsonObject RefreshTask::getRequestContent() const
* "requestUser": true/false // request the user structure
* }
*/
auto account = getMojangAccount();
QJsonObject req;
req.insert("clientToken", account->clientToken());
req.insert("accessToken", account->accessToken());
req.insert("clientToken", m_account->m_clientToken);
req.insert("accessToken", m_account->m_accessToken);
/*
{
auto currentProfile = account->currentProfile();
auto currentProfile = m_account->currentProfile();
QJsonObject profile;
profile.insert("id", currentProfile->id());
profile.insert("name", currentProfile->name());
@ -64,8 +63,6 @@ QJsonObject RefreshTask::getRequestContent() const
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.";
@ -80,7 +77,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
QLOG_ERROR() << "Server didn't send a client token.";
return false;
}
if (!account->clientToken().isEmpty() && clientToken != account->clientToken())
if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken)
{
// The server changed our client token! Obey its wishes, but complain. That's what I do
// for my parents, so...
@ -104,7 +101,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
// profile)
QJsonObject currentProfile = responseData.value("selectedProfile").toObject();
QString currentProfileId = currentProfile.value("id").toString("");
if (account->currentProfile()->id() != currentProfileId)
if (m_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.";
@ -132,8 +129,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
// we've succeeded.
QLOG_DEBUG() << "Finished reading refresh response.";
// Reset the access token.
account->setAccessToken(accessToken);
account->propagateChange();
m_account->m_accessToken = accessToken;
return true;
}

View File

@ -30,7 +30,7 @@ class RefreshTask : public YggdrasilTask
{
Q_OBJECT
public:
RefreshTask(MojangAccountPtr account, QObject *parent = 0);
RefreshTask(MojangAccount * account, QObject *parent = 0);
protected:
virtual QJsonObject getRequestContent() const;

View File

@ -26,7 +26,7 @@
#include "logger/QsLog.h"
ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent)
ValidateTask::ValidateTask(MojangAccount * account, QObject *parent)
: YggdrasilTask(account, parent)
{
}
@ -34,7 +34,7 @@ ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent)
QJsonObject ValidateTask::getRequestContent() const
{
QJsonObject req;
req.insert("accessToken", getMojangAccount()->accessToken());
req.insert("accessToken", m_account->m_accessToken);
return req;
}

View File

@ -28,7 +28,7 @@ class ValidateTask : public YggdrasilTask
{
Q_OBJECT
public:
ValidateTask(MojangAccountPtr account, QObject *parent = 0);
ValidateTask(MojangAccount *account, QObject *parent = 0);
protected:
virtual QJsonObject getRequestContent() const;

View File

@ -83,10 +83,7 @@ void MojangAccountList::removeAccount(QModelIndex index)
MojangAccountPtr MojangAccountList::activeAccount() const
{
if (m_activeAccount.isEmpty())
return nullptr;
else
return findAccount(m_activeAccount);
return m_activeAccount;
}
void MojangAccountList::setActiveAccount(const QString &username)
@ -94,14 +91,14 @@ void MojangAccountList::setActiveAccount(const QString &username)
beginResetModel();
if (username.isEmpty())
{
m_activeAccount = "";
m_activeAccount = nullptr;
}
else
{
for (MojangAccountPtr account : m_accounts)
{
if (account->username() == username)
m_activeAccount = username;
m_activeAccount = account;
}
}
endResetModel();
@ -152,7 +149,7 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const
switch (index.column())
{
case ActiveColumn:
return account->username() == m_activeAccount;
return account == m_activeAccount;
case NameColumn:
return account->username();
@ -297,11 +294,9 @@ bool MojangAccountList::loadList(const QString &filePath)
QLOG_WARN() << "Failed to load an account.";
}
}
endResetModel();
// Load the active account.
m_activeAccount = root.value("activeAccount").toString("");
m_activeAccount = findAccount(root.value("activeAccount").toString(""));
endResetModel();
return true;
}
@ -336,8 +331,11 @@ bool MojangAccountList::saveList(const QString &filePath)
// Insert the account list into the root object.
root.insert("accounts", accounts);
// Save the active account.
root.insert("activeAccount", m_activeAccount);
if(m_activeAccount)
{
// Save the active account.
root.insert("activeAccount", m_activeAccount->username());
}
// Create a JSON document object to convert our JSON to bytes.
QJsonDocument doc(root);

View File

@ -161,10 +161,9 @@ protected:
QList<MojangAccountPtr> m_accounts;
/*!
* Username of the account that is currently active.
* Empty string if no account is active.
* Account that is currently active.
*/
QString m_activeAccount;
MojangAccountPtr m_activeAccount;
//! Path to the account list file. Empty string if there isn't one.
QString m_listFilePath;