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:
parent
613699b362
commit
f028aa76bc
@ -69,10 +69,6 @@
|
|||||||
#include "logic/lists/IconList.h"
|
#include "logic/lists/IconList.h"
|
||||||
#include "logic/lists/JavaVersionList.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/BaseInstance.h"
|
||||||
#include "logic/InstanceFactory.h"
|
#include "logic/InstanceFactory.h"
|
||||||
#include "logic/MinecraftProcess.h"
|
#include "logic/MinecraftProcess.h"
|
||||||
@ -210,9 +206,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
|
|
||||||
for(AccountProfile profile : account->profiles())
|
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(
|
auto action = CacheDownload::make(
|
||||||
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name() + ".png"),
|
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name + ".png"),
|
||||||
meta);
|
meta);
|
||||||
job->addNetAction(action);
|
job->addNetAction(action);
|
||||||
meta->stale = true;
|
meta->stale = true;
|
||||||
@ -310,9 +306,9 @@ void MainWindow::repopulateAccountsMenu()
|
|||||||
section->setEnabled(false);
|
section->setEnabled(false);
|
||||||
accountMenu->addAction(section);
|
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->setData(account->username());
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
if(active_username == account->username())
|
if(active_username == account->username())
|
||||||
@ -320,7 +316,7 @@ void MainWindow::repopulateAccountsMenu()
|
|||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
action->setIcon(SkinUtils::getFaceFromCache(profile.name()));
|
action->setIcon(SkinUtils::getFaceFromCache(profile.name));
|
||||||
accountMenu->addAction(action);
|
accountMenu->addAction(action);
|
||||||
connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
|
connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount()));
|
||||||
}
|
}
|
||||||
@ -378,7 +374,7 @@ void MainWindow::activeAccountChanged()
|
|||||||
const AccountProfile *profile = account->currentProfile();
|
const AccountProfile *profile = account->currentProfile();
|
||||||
if (profile != nullptr)
|
if (profile != nullptr)
|
||||||
{
|
{
|
||||||
accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->name()));
|
accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,6 +786,7 @@ void MainWindow::doLaunch()
|
|||||||
void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
|
void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
|
||||||
{
|
{
|
||||||
// We'll need to validate the access token to make sure the account is still logged in.
|
// We'll need to validate the access token to make sure the account is still logged in.
|
||||||
|
/*
|
||||||
ProgressDialog progDialog(this);
|
ProgressDialog progDialog(this);
|
||||||
RefreshTask refreshtask(account, &progDialog);
|
RefreshTask refreshtask(account, &progDialog);
|
||||||
progDialog.exec(&refreshtask);
|
progDialog.exec(&refreshtask);
|
||||||
@ -829,10 +826,12 @@ void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
|
|||||||
QMessageBox::Warning, QMessageBox::Ok)->exec();
|
QMessageBox::Warning, QMessageBox::Ok)->exec();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMsg)
|
bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMsg)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
EditAccountDialog passDialog(errorMsg, this, EditAccountDialog::PasswordField);
|
EditAccountDialog passDialog(errorMsg, this, EditAccountDialog::PasswordField);
|
||||||
if (passDialog.exec() == QDialog::Accepted)
|
if (passDialog.exec() == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
@ -848,7 +847,8 @@ bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMs
|
|||||||
return doRefreshToken(account, authTask.failReason());
|
return doRefreshToken(account, authTask.failReason());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return false;
|
else return false;*/
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)
|
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include <logger/QsLog.h>
|
#include <logger/QsLog.h>
|
||||||
|
|
||||||
#include <logic/auth/flows/AuthenticateTask.h>
|
|
||||||
#include <logic/net/NetJob.h>
|
#include <logic/net/NetJob.h>
|
||||||
|
|
||||||
#include <gui/dialogs/EditAccountDialog.h>
|
#include <gui/dialogs/EditAccountDialog.h>
|
||||||
@ -117,8 +116,8 @@ void AccountListDialog::addAccount(const QString& errMsg)
|
|||||||
QString username(loginDialog.username());
|
QString username(loginDialog.username());
|
||||||
QString password(loginDialog.password());
|
QString password(loginDialog.password());
|
||||||
|
|
||||||
MojangAccountPtr account = MojangAccountPtr(new MojangAccount(username));
|
MojangAccountPtr account = MojangAccount::createFromUsername(username);
|
||||||
|
/*
|
||||||
ProgressDialog progDialog(this);
|
ProgressDialog progDialog(this);
|
||||||
AuthenticateTask authTask(account, password, &progDialog);
|
AuthenticateTask authTask(account, password, &progDialog);
|
||||||
if (progDialog.exec(&authTask))
|
if (progDialog.exec(&authTask))
|
||||||
@ -132,9 +131,9 @@ void AccountListDialog::addAccount(const QString& errMsg)
|
|||||||
|
|
||||||
for(AccountProfile profile : account->profiles())
|
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(
|
auto action = CacheDownload::make(
|
||||||
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name() + ".png"),
|
QUrl("http://skins.minecraft.net/MinecraftSkins/" + profile.name + ".png"),
|
||||||
meta);
|
meta);
|
||||||
job->addNetAction(action);
|
job->addNetAction(action);
|
||||||
meta->stale = true;
|
meta->stale = true;
|
||||||
@ -142,5 +141,6 @@ void AccountListDialog::addAccount(const QString& errMsg)
|
|||||||
|
|
||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
#include <logger/QsLog.h>
|
#include <logger/QsLog.h>
|
||||||
|
|
||||||
#include <logic/auth/flows/AuthenticateTask.h>
|
|
||||||
|
|
||||||
#include <gui/dialogs/ProgressDialog.h>
|
#include <gui/dialogs/ProgressDialog.h>
|
||||||
|
|
||||||
#include <MultiMC.h>
|
#include <MultiMC.h>
|
||||||
|
@ -105,7 +105,7 @@ MinecraftProcess *LegacyInstance::prepareForLaunch(MojangAccountPtr account)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
args << "-jar" << LAUNCHER_FILE;
|
args << "-jar" << LAUNCHER_FILE;
|
||||||
args << account->currentProfile()->name();
|
args << account->currentProfile()->name;
|
||||||
args << account->sessionId();
|
args << account->sessionId();
|
||||||
args << windowTitle;
|
args << windowTitle;
|
||||||
args << windowSize;
|
args << windowSize;
|
||||||
|
@ -75,20 +75,22 @@ QString MinecraftProcess::censorPrivateInfo(QString in)
|
|||||||
{
|
{
|
||||||
if(!m_account)
|
if(!m_account)
|
||||||
return in;
|
return in;
|
||||||
else
|
|
||||||
{
|
|
||||||
QString sessionId = m_account->sessionId();
|
QString sessionId = m_account->sessionId();
|
||||||
QString accessToken = m_account->accessToken();
|
QString accessToken = m_account->accessToken();
|
||||||
QString clientToken = m_account->clientToken();
|
QString clientToken = m_account->clientToken();
|
||||||
QString profileId = m_account->currentProfile()->id();
|
|
||||||
QString profileName = m_account->currentProfile()->name();
|
|
||||||
in.replace(sessionId, "<SESSION ID>");
|
in.replace(sessionId, "<SESSION ID>");
|
||||||
in.replace(accessToken, "<ACCESS TOKEN>");
|
in.replace(accessToken, "<ACCESS TOKEN>");
|
||||||
in.replace(clientToken, "<CLIENT TOKEN>");
|
in.replace(clientToken, "<CLIENT TOKEN>");
|
||||||
|
auto profile = m_account->currentProfile();
|
||||||
|
if(profile)
|
||||||
|
{
|
||||||
|
QString profileId = profile->id;
|
||||||
|
QString profileName = profile->name;
|
||||||
in.replace(profileId, "<PROFILE ID>");
|
in.replace(profileId, "<PROFILE ID>");
|
||||||
in.replace(profileName, "<PROFILE NAME>");
|
in.replace(profileName, "<PROFILE NAME>");
|
||||||
return in;
|
|
||||||
}
|
}
|
||||||
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
// console window
|
// console window
|
||||||
|
@ -77,8 +77,8 @@ QStringList OneSixInstance::processMinecraftArgs(MojangAccountPtr account)
|
|||||||
token_mapping["auth_username"] = account->username();
|
token_mapping["auth_username"] = account->username();
|
||||||
token_mapping["auth_session"] = account->sessionId();
|
token_mapping["auth_session"] = account->sessionId();
|
||||||
token_mapping["auth_access_token"] = account->accessToken();
|
token_mapping["auth_access_token"] = account->accessToken();
|
||||||
token_mapping["auth_player_name"] = account->currentProfile()->name();
|
token_mapping["auth_player_name"] = account->currentProfile()->name;
|
||||||
token_mapping["auth_uuid"] = account->currentProfile()->id();
|
token_mapping["auth_uuid"] = account->currentProfile()->id;
|
||||||
|
|
||||||
// this is for offline?:
|
// this is for offline?:
|
||||||
/*
|
/*
|
||||||
|
@ -16,113 +16,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MojangAccount.h"
|
#include "MojangAccount.h"
|
||||||
|
#include "flows/RefreshTask.h"
|
||||||
|
#include "flows/AuthenticateTask.h"
|
||||||
|
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
#include <logger/QsLog.h>
|
#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)
|
MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
|
||||||
{
|
{
|
||||||
// The JSON object must at least have a username for it to be valid.
|
// 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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileList profiles;
|
QList<AccountProfile> profiles;
|
||||||
for (QJsonValue profileVal : profileArray)
|
for (QJsonValue profileVal : profileArray)
|
||||||
{
|
{
|
||||||
QJsonObject profileObject = profileVal.toObject();
|
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.";
|
QLOG_WARN() << "Unable to load a profile because it was missing an ID or a name.";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
profiles.append(AccountProfile(id, name));
|
profiles.append({id, name});
|
||||||
}
|
}
|
||||||
|
|
||||||
MojangAccountPtr account(new MojangAccount(username, clientToken, accessToken));
|
MojangAccountPtr account(new MojangAccount());
|
||||||
account->loadProfiles(profiles);
|
account->m_username = username;
|
||||||
|
account->m_clientToken = clientToken;
|
||||||
|
account->m_accessToken = accessToken;
|
||||||
|
account->m_profiles = profiles;
|
||||||
|
|
||||||
// Get the currently selected profile.
|
// Get the currently selected profile.
|
||||||
QString currentProfile = object.value("activeProfile").toString("");
|
QString currentProfile = object.value("activeProfile").toString("");
|
||||||
if (!currentProfile.isEmpty())
|
if (!currentProfile.isEmpty())
|
||||||
account->setProfile(currentProfile);
|
account->setCurrentProfile(currentProfile);
|
||||||
|
|
||||||
return account;
|
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;
|
QJsonObject json;
|
||||||
json.insert("username", username());
|
json.insert("username", m_username);
|
||||||
json.insert("clientToken", clientToken());
|
json.insert("clientToken", m_clientToken);
|
||||||
json.insert("accessToken", accessToken());
|
json.insert("accessToken", m_accessToken);
|
||||||
|
|
||||||
QJsonArray profileArray;
|
QJsonArray profileArray;
|
||||||
for (AccountProfile profile : m_profiles)
|
for (AccountProfile profile : m_profiles)
|
||||||
{
|
{
|
||||||
QJsonObject profileObj;
|
QJsonObject profileObj;
|
||||||
profileObj.insert("id", profile.id());
|
profileObj.insert("id", profile.id);
|
||||||
profileObj.insert("name", profile.name());
|
profileObj.insert("name", profile.name);
|
||||||
profileArray.append(profileObj);
|
profileArray.append(profileObj);
|
||||||
}
|
}
|
||||||
json.insert("profiles", profileArray);
|
json.insert("profiles", profileArray);
|
||||||
|
|
||||||
if (currentProfile() != nullptr)
|
if (m_currentProfile != -1)
|
||||||
json.insert("activeProfile", currentProfile()->id());
|
json.insert("activeProfile", currentProfile()->id);
|
||||||
|
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MojangAccount::setCurrentProfile(const QString &profileId)
|
||||||
AccountProfile::AccountProfile(const QString& id, const QString& name)
|
|
||||||
{
|
{
|
||||||
m_id = id;
|
for (int i = 0; i < m_profiles.length(); i++)
|
||||||
m_name = name;
|
{
|
||||||
|
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;
|
if(m_currentProfile == -1)
|
||||||
m_name = other.m_name;
|
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();
|
emit changed();
|
||||||
}
|
}
|
||||||
|
@ -23,34 +23,25 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
class YggdrasilTask;
|
||||||
class MojangAccount;
|
class MojangAccount;
|
||||||
|
|
||||||
typedef std::shared_ptr<MojangAccount> MojangAccountPtr;
|
typedef std::shared_ptr<MojangAccount> MojangAccountPtr;
|
||||||
Q_DECLARE_METATYPE(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,
|
* 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
|
* 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.
|
* we don't have to rip the code to pieces to add it later.
|
||||||
*/
|
*/
|
||||||
class AccountProfile
|
struct AccountProfile
|
||||||
{
|
{
|
||||||
public:
|
QString id;
|
||||||
AccountProfile(const QString &id, const QString &name);
|
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
|
struct User
|
||||||
{
|
{
|
||||||
QString id;
|
QString id;
|
||||||
@ -59,6 +50,13 @@ struct User
|
|||||||
QList<QPair<QString, QString>> properties;
|
QList<QPair<QString, QString>> properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum AccountStatus
|
||||||
|
{
|
||||||
|
NotVerified,
|
||||||
|
Verified,
|
||||||
|
Online
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that stores information about a certain Mojang account.
|
* Object that stores information about a certain Mojang account.
|
||||||
*
|
*
|
||||||
@ -68,106 +66,112 @@ struct User
|
|||||||
class MojangAccount : public QObject
|
class MojangAccount : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public: /* construction */
|
||||||
/**
|
//! Do not copy accounts. ever.
|
||||||
* Constructs a new MojangAccount with the given username.
|
explicit MojangAccount(const MojangAccount &other, QObject *parent) = delete;
|
||||||
* The client token will be generated automatically and the access token will be blank.
|
|
||||||
*/
|
|
||||||
explicit MojangAccount(const QString &username, QObject *parent = 0);
|
|
||||||
|
|
||||||
/**
|
//! Default constructor
|
||||||
* Constructs a new MojangAccount with the given username, client token, and access token.
|
explicit MojangAccount(QObject *parent = 0) : QObject(parent) {};
|
||||||
*/
|
|
||||||
explicit MojangAccount(const QString &username, const QString &clientToken,
|
|
||||||
const QString &accessToken, QObject *parent = 0);
|
|
||||||
|
|
||||||
/**
|
//! Creates an empty account for the specified user name.
|
||||||
* Constructs a new MojangAccount matching the given account.
|
static MojangAccountPtr createFromUsername(const QString &username);
|
||||||
*/
|
|
||||||
MojangAccount(const MojangAccount &other, QObject *parent);
|
|
||||||
|
|
||||||
/**
|
//! Loads a MojangAccount from the given JSON object.
|
||||||
* 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.
|
||||||
* Saves a MojangAccount to a JSON object and returns it.
|
QJsonObject saveToJson() const;
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
public: /* manipulation */
|
||||||
/**
|
/**
|
||||||
* Sets the currently selected profile to the profile with the given ID string.
|
* 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:
|
signals:
|
||||||
/**
|
/**
|
||||||
* This isgnal is emitted whrn the account changes
|
* This signal is emitted when the account changes
|
||||||
*/
|
*/
|
||||||
void changed();
|
void changed();
|
||||||
|
|
||||||
protected:
|
// TODO: better signalling for the various possible state changes - especially errors
|
||||||
|
|
||||||
|
protected: /* variables */
|
||||||
QString m_username;
|
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_clientToken;
|
||||||
QString m_accessToken; // Blank if not logged in.
|
|
||||||
int m_currentProfile; // Index of the selected profile within the list of available
|
// Blank if not logged in.
|
||||||
|
QString m_accessToken;
|
||||||
|
|
||||||
|
// Index of the selected profile within the list of available
|
||||||
// profiles. -1 if nothing is selected.
|
// profiles. -1 if nothing is selected.
|
||||||
ProfileList m_profiles; // List of available profiles.
|
int m_currentProfile = -1;
|
||||||
User m_user; // the user structure, whatever it is.
|
|
||||||
|
// 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;
|
||||||
};
|
};
|
||||||
|
@ -25,10 +25,9 @@
|
|||||||
#include <MultiMC.h>
|
#include <MultiMC.h>
|
||||||
#include <logic/auth/MojangAccount.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()
|
YggdrasilTask::~YggdrasilTask()
|
||||||
@ -81,7 +80,8 @@ void YggdrasilTask::processReply(QNetworkReply *reply)
|
|||||||
|
|
||||||
if (responseCode == 200)
|
if (responseCode == 200)
|
||||||
{
|
{
|
||||||
// If the response code was 200, then there shouldn't be an error. Make sure anyways.
|
// 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,
|
// Also, sometimes an empty reply indicates success. If there was no data received,
|
||||||
// pass an empty json object to the processResponse function.
|
// 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)
|
||||||
@ -102,25 +102,34 @@ void YggdrasilTask::processReply(QNetworkReply *reply)
|
|||||||
}
|
}
|
||||||
else
|
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
|
else
|
||||||
{
|
{
|
||||||
// If the response code was not 200, then Yggdrasil may have given us information about the error.
|
// If the response code was not 200, then Yggdrasil may have given us information
|
||||||
// If we can parse the response, then get information from it. Otherwise just say there was an unknown error.
|
// 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)
|
if (jsonError.error == QJsonParseError::NoError)
|
||||||
{
|
{
|
||||||
// We were able to parse the server's response. Woo!
|
// 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.
|
// Call processError. If a subclass has overridden it then they'll handle their
|
||||||
QLOG_DEBUG() << "The request failed, but the server gave us an error message. Processing error.";
|
// stuff there.
|
||||||
|
QLOG_DEBUG() << "The request failed, but the server gave us an error message. "
|
||||||
|
"Processing error.";
|
||||||
emitFailed(processError(doc.object()));
|
emitFailed(processError(doc.object()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The server didn't say anything regarding the error. Give the user an unknown error.
|
// The server didn't say anything regarding the error. Give the user an unknown
|
||||||
QLOG_DEBUG() << "The request failed and the server gave no error message. Unknown error.";
|
// error.
|
||||||
emitFailed(tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(reply->errorString()));
|
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;
|
return this->m_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
MojangAccountPtr YggdrasilTask::getMojangAccount() const
|
|
||||||
{
|
|
||||||
return this->m_account;
|
|
||||||
}
|
|
||||||
|
@ -31,7 +31,7 @@ class YggdrasilTask : public Task
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit YggdrasilTask(MojangAccountPtr account, QObject *parent = 0);
|
explicit YggdrasilTask(MojangAccount * account, QObject *parent = 0);
|
||||||
~YggdrasilTask();
|
~YggdrasilTask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,11 +59,6 @@ public:
|
|||||||
QString m_cause;
|
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.
|
* Returns a pointer to a YggdrasilTask::Error object if an error has occurred.
|
||||||
* If no error has occurred, returns a null pointer.
|
* If no error has occurred, returns a null pointer.
|
||||||
@ -120,11 +115,11 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual QString getStateMessage(const State state) const;
|
virtual QString getStateMessage(const State state) const;
|
||||||
|
|
||||||
MojangAccountPtr m_account;
|
MojangAccount *m_account = nullptr;
|
||||||
|
|
||||||
QNetworkReply *m_netReply;
|
QNetworkReply *m_netReply;
|
||||||
|
|
||||||
Error *m_error;
|
Error *m_error = nullptr;
|
||||||
|
|
||||||
protected
|
protected
|
||||||
slots:
|
slots:
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
AuthenticateTask::AuthenticateTask(MojangAccountPtr account, const QString &password,
|
AuthenticateTask::AuthenticateTask(MojangAccount * account, const QString &password,
|
||||||
QObject *parent)
|
QObject *parent)
|
||||||
: YggdrasilTask(account, parent), m_password(password)
|
: YggdrasilTask(account, parent), m_password(password)
|
||||||
{
|
{
|
||||||
@ -59,14 +59,14 @@ QJsonObject AuthenticateTask::getRequestContent() const
|
|||||||
req.insert("agent", agent);
|
req.insert("agent", agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
req.insert("username", getMojangAccount()->username());
|
req.insert("username", m_account->username());
|
||||||
req.insert("password", m_password);
|
req.insert("password", m_password);
|
||||||
req.insert("requestUser", true);
|
req.insert("requestUser", true);
|
||||||
|
|
||||||
// If we already have a client token, give it to the server.
|
// If we already have a client token, give it to the server.
|
||||||
// Otherwise, let the server give us one.
|
// Otherwise, let the server give us one.
|
||||||
if (!getMojangAccount()->clientToken().isEmpty())
|
if (!m_account->m_clientToken.isEmpty())
|
||||||
req.insert("clientToken", getMojangAccount()->clientToken());
|
req.insert("clientToken", m_account->m_clientToken);
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
@ -88,8 +88,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
|
|||||||
QLOG_ERROR() << "Server didn't send a client token.";
|
QLOG_ERROR() << "Server didn't send a client token.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!getMojangAccount()->clientToken().isEmpty() &&
|
if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken)
|
||||||
clientToken != getMojangAccount()->clientToken())
|
|
||||||
{
|
{
|
||||||
// The server changed our client token! Obey its wishes, but complain. That's what I do
|
// The server changed our client token! Obey its wishes, but complain. That's what I do
|
||||||
// for my parents, so...
|
// 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.";
|
<< "'. This shouldn't happen, but it isn't really a big deal.";
|
||||||
}
|
}
|
||||||
// Set the client token.
|
// Set the client token.
|
||||||
getMojangAccount()->setClientToken(clientToken);
|
m_account->m_clientToken = clientToken;
|
||||||
|
|
||||||
// Now, we set the access token.
|
// Now, we set the access token.
|
||||||
QLOG_DEBUG() << "Getting 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.";
|
QLOG_ERROR() << "Server didn't send an access token.";
|
||||||
}
|
}
|
||||||
// Set the access token.
|
// Set the access token.
|
||||||
getMojangAccount()->setAccessToken(accessToken);
|
m_account->m_accessToken = accessToken;
|
||||||
|
|
||||||
// Now we load the list of available profiles.
|
// Now we load the list of available profiles.
|
||||||
// Mojang hasn't yet implemented the profile system,
|
// Mojang hasn't yet implemented the profile system,
|
||||||
@ -117,7 +116,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
|
|||||||
// don't have trouble implementing it later.
|
// don't have trouble implementing it later.
|
||||||
QLOG_DEBUG() << "Loading profile list.";
|
QLOG_DEBUG() << "Loading profile list.";
|
||||||
QJsonArray availableProfiles = responseData.value("availableProfiles").toArray();
|
QJsonArray availableProfiles = responseData.value("availableProfiles").toArray();
|
||||||
ProfileList loadedProfiles;
|
QList<AccountProfile> loadedProfiles;
|
||||||
for (auto iter : availableProfiles)
|
for (auto iter : availableProfiles)
|
||||||
{
|
{
|
||||||
QJsonObject profile = iter.toObject();
|
QJsonObject profile = iter.toObject();
|
||||||
@ -135,10 +134,10 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, add a new AccountProfile entry to the list.
|
// 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.
|
// 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.
|
// 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
|
||||||
@ -153,7 +152,7 @@ bool AuthenticateTask::processResponse(QJsonObject responseData)
|
|||||||
QLOG_ERROR() << "Server didn't specify a currently selected profile.";
|
QLOG_ERROR() << "Server didn't specify a currently selected profile.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!getMojangAccount()->setProfile(currentProfileId))
|
if (!m_account->setCurrentProfile(currentProfileId))
|
||||||
{
|
{
|
||||||
// TODO: Set an error to display to the user.
|
// TODO: Set an error to display to the user.
|
||||||
QLOG_ERROR() << "Server specified a selected profile that wasn't in the available "
|
QLOG_ERROR() << "Server specified a selected profile that wasn't in the available "
|
||||||
|
@ -30,7 +30,7 @@ class AuthenticateTask : public YggdrasilTask
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AuthenticateTask(MojangAccountPtr account, const QString &password, QObject *parent = 0);
|
AuthenticateTask(MojangAccount *account, const QString &password, QObject *parent = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QJsonObject getRequestContent() const;
|
virtual QJsonObject getRequestContent() const;
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
RefreshTask::RefreshTask(MojangAccountPtr account, QObject *parent)
|
RefreshTask::RefreshTask(MojangAccount *account, QObject *parent)
|
||||||
: YggdrasilTask(account, parent)
|
: YggdrasilTask(account, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -44,13 +44,12 @@ QJsonObject RefreshTask::getRequestContent() const
|
|||||||
* "requestUser": true/false // request the user structure
|
* "requestUser": true/false // request the user structure
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
auto account = getMojangAccount();
|
|
||||||
QJsonObject req;
|
QJsonObject req;
|
||||||
req.insert("clientToken", account->clientToken());
|
req.insert("clientToken", m_account->m_clientToken);
|
||||||
req.insert("accessToken", account->accessToken());
|
req.insert("accessToken", m_account->m_accessToken);
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
auto currentProfile = account->currentProfile();
|
auto currentProfile = m_account->currentProfile();
|
||||||
QJsonObject profile;
|
QJsonObject profile;
|
||||||
profile.insert("id", currentProfile->id());
|
profile.insert("id", currentProfile->id());
|
||||||
profile.insert("name", currentProfile->name());
|
profile.insert("name", currentProfile->name());
|
||||||
@ -64,8 +63,6 @@ QJsonObject RefreshTask::getRequestContent() const
|
|||||||
|
|
||||||
bool RefreshTask::processResponse(QJsonObject responseData)
|
bool RefreshTask::processResponse(QJsonObject responseData)
|
||||||
{
|
{
|
||||||
auto account = getMojangAccount();
|
|
||||||
|
|
||||||
// Read the response data. We need to get the client token, access token, and the selected
|
// Read the response data. We need to get the client token, access token, and the selected
|
||||||
// profile.
|
// profile.
|
||||||
QLOG_DEBUG() << "Processing authentication response.";
|
QLOG_DEBUG() << "Processing authentication response.";
|
||||||
@ -80,7 +77,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
|
|||||||
QLOG_ERROR() << "Server didn't send a client token.";
|
QLOG_ERROR() << "Server didn't send a client token.";
|
||||||
return false;
|
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
|
// The server changed our client token! Obey its wishes, but complain. That's what I do
|
||||||
// for my parents, so...
|
// for my parents, so...
|
||||||
@ -104,7 +101,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
|
|||||||
// profile)
|
// profile)
|
||||||
QJsonObject currentProfile = responseData.value("selectedProfile").toObject();
|
QJsonObject currentProfile = responseData.value("selectedProfile").toObject();
|
||||||
QString currentProfileId = currentProfile.value("id").toString("");
|
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.
|
// TODO: Set an error to display to the user.
|
||||||
QLOG_ERROR() << "Server didn't specify the same selected profile as ours.";
|
QLOG_ERROR() << "Server didn't specify the same selected profile as ours.";
|
||||||
@ -132,8 +129,7 @@ bool RefreshTask::processResponse(QJsonObject responseData)
|
|||||||
// we've succeeded.
|
// we've succeeded.
|
||||||
QLOG_DEBUG() << "Finished reading refresh response.";
|
QLOG_DEBUG() << "Finished reading refresh response.";
|
||||||
// Reset the access token.
|
// Reset the access token.
|
||||||
account->setAccessToken(accessToken);
|
m_account->m_accessToken = accessToken;
|
||||||
account->propagateChange();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class RefreshTask : public YggdrasilTask
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
RefreshTask(MojangAccountPtr account, QObject *parent = 0);
|
RefreshTask(MojangAccount * account, QObject *parent = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QJsonObject getRequestContent() const;
|
virtual QJsonObject getRequestContent() const;
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#include "logger/QsLog.h"
|
#include "logger/QsLog.h"
|
||||||
|
|
||||||
ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent)
|
ValidateTask::ValidateTask(MojangAccount * account, QObject *parent)
|
||||||
: YggdrasilTask(account, parent)
|
: YggdrasilTask(account, parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ ValidateTask::ValidateTask(MojangAccountPtr account, QObject *parent)
|
|||||||
QJsonObject ValidateTask::getRequestContent() const
|
QJsonObject ValidateTask::getRequestContent() const
|
||||||
{
|
{
|
||||||
QJsonObject req;
|
QJsonObject req;
|
||||||
req.insert("accessToken", getMojangAccount()->accessToken());
|
req.insert("accessToken", m_account->m_accessToken);
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class ValidateTask : public YggdrasilTask
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ValidateTask(MojangAccountPtr account, QObject *parent = 0);
|
ValidateTask(MojangAccount *account, QObject *parent = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual QJsonObject getRequestContent() const;
|
virtual QJsonObject getRequestContent() const;
|
||||||
|
@ -83,10 +83,7 @@ void MojangAccountList::removeAccount(QModelIndex index)
|
|||||||
|
|
||||||
MojangAccountPtr MojangAccountList::activeAccount() const
|
MojangAccountPtr MojangAccountList::activeAccount() const
|
||||||
{
|
{
|
||||||
if (m_activeAccount.isEmpty())
|
return m_activeAccount;
|
||||||
return nullptr;
|
|
||||||
else
|
|
||||||
return findAccount(m_activeAccount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MojangAccountList::setActiveAccount(const QString &username)
|
void MojangAccountList::setActiveAccount(const QString &username)
|
||||||
@ -94,14 +91,14 @@ void MojangAccountList::setActiveAccount(const QString &username)
|
|||||||
beginResetModel();
|
beginResetModel();
|
||||||
if (username.isEmpty())
|
if (username.isEmpty())
|
||||||
{
|
{
|
||||||
m_activeAccount = "";
|
m_activeAccount = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (MojangAccountPtr account : m_accounts)
|
for (MojangAccountPtr account : m_accounts)
|
||||||
{
|
{
|
||||||
if (account->username() == username)
|
if (account->username() == username)
|
||||||
m_activeAccount = username;
|
m_activeAccount = account;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
@ -152,7 +149,7 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const
|
|||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
case ActiveColumn:
|
case ActiveColumn:
|
||||||
return account->username() == m_activeAccount;
|
return account == m_activeAccount;
|
||||||
|
|
||||||
case NameColumn:
|
case NameColumn:
|
||||||
return account->username();
|
return account->username();
|
||||||
@ -297,11 +294,9 @@ bool MojangAccountList::loadList(const QString &filePath)
|
|||||||
QLOG_WARN() << "Failed to load an account.";
|
QLOG_WARN() << "Failed to load an account.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endResetModel();
|
|
||||||
|
|
||||||
// Load the active account.
|
// Load the active account.
|
||||||
m_activeAccount = root.value("activeAccount").toString("");
|
m_activeAccount = findAccount(root.value("activeAccount").toString(""));
|
||||||
|
endResetModel();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,8 +331,11 @@ bool MojangAccountList::saveList(const QString &filePath)
|
|||||||
// Insert the account list into the root object.
|
// Insert the account list into the root object.
|
||||||
root.insert("accounts", accounts);
|
root.insert("accounts", accounts);
|
||||||
|
|
||||||
|
if(m_activeAccount)
|
||||||
|
{
|
||||||
// Save the active account.
|
// Save the active account.
|
||||||
root.insert("activeAccount", m_activeAccount);
|
root.insert("activeAccount", m_activeAccount->username());
|
||||||
|
}
|
||||||
|
|
||||||
// Create a JSON document object to convert our JSON to bytes.
|
// Create a JSON document object to convert our JSON to bytes.
|
||||||
QJsonDocument doc(root);
|
QJsonDocument doc(root);
|
||||||
|
@ -161,10 +161,9 @@ protected:
|
|||||||
QList<MojangAccountPtr> m_accounts;
|
QList<MojangAccountPtr> m_accounts;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Username of the account that is currently active.
|
* Account that is currently active.
|
||||||
* Empty string if no account is active.
|
|
||||||
*/
|
*/
|
||||||
QString m_activeAccount;
|
MojangAccountPtr m_activeAccount;
|
||||||
|
|
||||||
//! Path to the account list file. Empty string if there isn't one.
|
//! Path to the account list file. Empty string if there isn't one.
|
||||||
QString m_listFilePath;
|
QString m_listFilePath;
|
||||||
|
Loading…
Reference in New Issue
Block a user