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:
		| @@ -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 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 profileId = profile->id; | ||||||
| 		QString accessToken = m_account->accessToken(); | 		QString profileName = profile->name; | ||||||
| 		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>"); |  | ||||||
| 		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. | ||||||
| 							// profiles. -1 if nothing is selected. | 	QString m_accessToken; | ||||||
| 	ProfileList m_profiles; // List of available profiles. |  | ||||||
| 	User m_user;			// the user structure, whatever it is. | 	// 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; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -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,8 +80,9 @@ 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 | ||||||
| 			// Also, sometimes an empty reply indicates success. If there was no data received,  | 			// anyways. | ||||||
|  | 			// 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); | ||||||
|  |  | ||||||
| 	// Save the active account. | 	if(m_activeAccount) | ||||||
| 	root.insert("activeAccount", m_activeAccount); | 	{ | ||||||
|  | 		// Save the active account. | ||||||
|  | 		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; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user