aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-12-04 01:18:05 +0100
committerPetr Mrázek <peterix@gmail.com>2021-12-04 01:18:05 +0100
commit3c46d8a412956a759f61ae802c540ef72d00b35d (patch)
treef16564ba6be96b68ba5257a982c144320fff7911 /launcher
parentffcef673de9fe848a92d23e02a2abed8df16eb9f (diff)
downloadPrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.gz
PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.bz2
PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.zip
GH-4071 Heavily refactor and rearchitect account system
This makes the account system much more modular and makes it treat errors as something recoverable, unless they come directly from the MSA refresh token becoming invalid.
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp1
-rw-r--r--launcher/CMakeLists.txt68
-rw-r--r--launcher/LaunchController.cpp219
-rw-r--r--launcher/minecraft/auth/AccountData.h15
-rw-r--r--launcher/minecraft/auth/AccountList.cpp138
-rw-r--r--launcher/minecraft/auth/AccountList.h28
-rw-r--r--launcher/minecraft/auth/AccountTask.cpp75
-rw-r--r--launcher/minecraft/auth/AccountTask.h72
-rw-r--r--launcher/minecraft/auth/AuthRequest.cpp (renamed from launcher/minecraft/auth/flows/AuthRequest.cpp)10
-rw-r--r--launcher/minecraft/auth/AuthRequest.h (renamed from launcher/minecraft/auth/flows/AuthRequest.h)8
-rw-r--r--launcher/minecraft/auth/AuthStep.cpp7
-rw-r--r--launcher/minecraft/auth/AuthStep.h33
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.cpp259
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.h37
-rw-r--r--launcher/minecraft/auth/Parsers.cpp (renamed from launcher/minecraft/auth/flows/Parsers.cpp)2
-rw-r--r--launcher/minecraft/auth/Parsers.h (renamed from launcher/minecraft/auth/flows/Parsers.h)4
-rw-r--r--launcher/minecraft/auth/Yggdrasil.cpp (renamed from launcher/minecraft/auth/flows/Yggdrasil.cpp)34
-rw-r--r--launcher/minecraft/auth/Yggdrasil.h (renamed from launcher/minecraft/auth/flows/Yggdrasil.h)22
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.cpp671
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.h110
-rw-r--r--launcher/minecraft/auth/flows/AuthFlow.cpp71
-rw-r--r--launcher/minecraft/auth/flows/AuthFlow.h45
-rw-r--r--launcher/minecraft/auth/flows/MSA.cpp37
-rw-r--r--launcher/minecraft/auth/flows/MSA.h22
-rw-r--r--launcher/minecraft/auth/flows/MSAInteractive.cpp22
-rw-r--r--launcher/minecraft/auth/flows/MSAInteractive.h13
-rw-r--r--launcher/minecraft/auth/flows/MSASilent.cpp16
-rw-r--r--launcher/minecraft/auth/flows/MSASilent.h13
-rw-r--r--launcher/minecraft/auth/flows/Mojang.cpp27
-rw-r--r--launcher/minecraft/auth/flows/Mojang.h26
-rw-r--r--launcher/minecraft/auth/flows/MojangLogin.cpp18
-rw-r--r--launcher/minecraft/auth/flows/MojangLogin.h17
-rw-r--r--launcher/minecraft/auth/flows/MojangRefresh.cpp17
-rw-r--r--launcher/minecraft/auth/flows/MojangRefresh.h10
-rw-r--r--launcher/minecraft/auth/steps/EntitlementsStep.cpp53
-rw-r--r--launcher/minecraft/auth/steps/EntitlementsStep.h25
-rw-r--r--launcher/minecraft/auth/steps/GetSkinStep.cpp43
-rw-r--r--launcher/minecraft/auth/steps/GetSkinStep.h22
-rw-r--r--launcher/minecraft/auth/steps/LauncherLoginStep.cpp78
-rw-r--r--launcher/minecraft/auth/steps/LauncherLoginStep.h22
-rw-r--r--launcher/minecraft/auth/steps/MSAStep.cpp111
-rw-r--r--launcher/minecraft/auth/steps/MSAStep.h32
-rw-r--r--launcher/minecraft/auth/steps/MigrationEligibilityStep.cpp45
-rw-r--r--launcher/minecraft/auth/steps/MigrationEligibilityStep.h22
-rw-r--r--launcher/minecraft/auth/steps/MinecraftProfileStep.cpp83
-rw-r--r--launcher/minecraft/auth/steps/MinecraftProfileStep.h22
-rw-r--r--launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp158
-rw-r--r--launcher/minecraft/auth/steps/XboxAuthorizationStep.h34
-rw-r--r--launcher/minecraft/auth/steps/XboxProfileStep.cpp73
-rw-r--r--launcher/minecraft/auth/steps/XboxProfileStep.h22
-rw-r--r--launcher/minecraft/auth/steps/XboxUserStep.cpp68
-rw-r--r--launcher/minecraft/auth/steps/XboxUserStep.h22
-rw-r--r--launcher/minecraft/auth/steps/YggdrasilStep.cpp51
-rw-r--r--launcher/minecraft/auth/steps/YggdrasilStep.h28
-rw-r--r--launcher/minecraft/services/CapeChange.cpp8
-rw-r--r--launcher/minecraft/services/CapeChange.h5
-rw-r--r--launcher/minecraft/services/SkinDelete.cpp6
-rw-r--r--launcher/minecraft/services/SkinDelete.h6
-rw-r--r--launcher/minecraft/services/SkinUpload.cpp6
-rw-r--r--launcher/minecraft/services/SkinUpload.h5
-rw-r--r--launcher/ui/dialogs/LoginDialog.cpp2
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.cpp2
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp10
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.cpp15
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp16
-rw-r--r--launcher/ui/widgets/ErrorFrame.cpp134
-rw-r--r--launcher/ui/widgets/ErrorFrame.h49
-rw-r--r--launcher/ui/widgets/ErrorFrame.ui92
68 files changed, 2098 insertions, 1439 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 37724038..2d0c81bb 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -827,6 +827,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
qDebug() << "Loading accounts...";
m_accounts->setListFilePath("accounts.json", true);
m_accounts->loadList();
+ m_accounts->fillQueue();
qDebug() << "<> Accounts loaded.";
}
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 08c878d1..2dfc78b5 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -196,36 +196,52 @@ set(ICONS_SOURCES
# Support for Minecraft instances and launch
set(MINECRAFT_SOURCES
# Minecraft support
- minecraft/auth/AccountData.h
minecraft/auth/AccountData.cpp
- minecraft/auth/AccountTask.h
+ minecraft/auth/AccountData.h
+ minecraft/auth/AccountList.cpp
+ minecraft/auth/AccountList.h
minecraft/auth/AccountTask.cpp
- minecraft/auth/AuthSession.h
+ minecraft/auth/AccountTask.h
+ minecraft/auth/AuthRequest.cpp
+ minecraft/auth/AuthRequest.h
minecraft/auth/AuthSession.cpp
- minecraft/auth/AccountList.h
- minecraft/auth/AccountList.cpp
- minecraft/auth/MinecraftAccount.h
+ minecraft/auth/AuthSession.h
+ minecraft/auth/AuthStep.cpp
+ minecraft/auth/AuthStep.h
minecraft/auth/MinecraftAccount.cpp
- minecraft/auth/flows/AuthContext.h
- minecraft/auth/flows/AuthContext.cpp
- minecraft/auth/flows/AuthRequest.h
- minecraft/auth/flows/AuthRequest.cpp
-
- minecraft/auth/flows/MSAInteractive.h
- minecraft/auth/flows/MSAInteractive.cpp
- minecraft/auth/flows/MSASilent.h
- minecraft/auth/flows/MSASilent.cpp
-
- minecraft/auth/flows/MojangLogin.h
- minecraft/auth/flows/MojangLogin.cpp
- minecraft/auth/flows/MojangRefresh.h
- minecraft/auth/flows/MojangRefresh.cpp
-
- minecraft/auth/flows/Yggdrasil.h
- minecraft/auth/flows/Yggdrasil.cpp
-
- minecraft/auth/flows/Parsers.h
- minecraft/auth/flows/Parsers.cpp
+ minecraft/auth/MinecraftAccount.h
+ minecraft/auth/Parsers.cpp
+ minecraft/auth/Parsers.h
+ minecraft/auth/Yggdrasil.cpp
+ minecraft/auth/Yggdrasil.h
+
+ minecraft/auth/flows/AuthFlow.cpp
+ minecraft/auth/flows/AuthFlow.h
+ minecraft/auth/flows/Mojang.cpp
+ minecraft/auth/flows/Mojang.h
+ minecraft/auth/flows/MSA.cpp
+ minecraft/auth/flows/MSA.h
+
+ minecraft/auth/steps/EntitlementsStep.cpp
+ minecraft/auth/steps/EntitlementsStep.h
+ minecraft/auth/steps/GetSkinStep.cpp
+ minecraft/auth/steps/GetSkinStep.h
+ minecraft/auth/steps/LauncherLoginStep.cpp
+ minecraft/auth/steps/LauncherLoginStep.h
+ minecraft/auth/steps/MigrationEligibilityStep.cpp
+ minecraft/auth/steps/MigrationEligibilityStep.h
+ minecraft/auth/steps/MinecraftProfileStep.cpp
+ minecraft/auth/steps/MinecraftProfileStep.h
+ minecraft/auth/steps/MSAStep.cpp
+ minecraft/auth/steps/MSAStep.h
+ minecraft/auth/steps/XboxAuthorizationStep.cpp
+ minecraft/auth/steps/XboxAuthorizationStep.h
+ minecraft/auth/steps/XboxProfileStep.cpp
+ minecraft/auth/steps/XboxProfileStep.h
+ minecraft/auth/steps/XboxUserStep.cpp
+ minecraft/auth/steps/XboxUserStep.h
+ minecraft/auth/steps/YggdrasilStep.cpp
+ minecraft/auth/steps/YggdrasilStep.h
minecraft/gameoptions/GameOptions.h
minecraft/gameoptions/GameOptions.cpp
diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp
index 8bd5732f..39fec9e6 100644
--- a/launcher/LaunchController.cpp
+++ b/launcher/LaunchController.cpp
@@ -35,6 +35,8 @@ void LaunchController::executeTask()
return;
}
+ JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
+
login();
}
@@ -90,8 +92,6 @@ void LaunchController::decideAccount()
void LaunchController::login() {
- JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
-
decideAccount();
// if no account is selected, we bail
@@ -113,120 +113,107 @@ void LaunchController::login() {
{
m_session = std::make_shared<AuthSession>();
m_session->wants_online = m_online;
- shared_qobject_ptr<AccountTask> task;
- if(!password.isNull()) {
- task = m_accountToUse->login(m_session, password);
- }
- else {
- task = m_accountToUse->refresh(m_session);
- }
- if (task)
- {
- // We'll need to validate the access token to make sure the account
- // is still logged in.
- ProgressDialog progDialog(m_parentWidget);
- if (m_online)
- {
- progDialog.setSkipButton(true, tr("Play Offline"));
- }
- progDialog.execWithTask(task.get());
- if (!task->wasSuccessful())
- {
- auto failReasonNew = task->failReason();
- if(failReasonNew == "Invalid token." || failReasonNew == "Invalid Signature")
- {
- // account->invalidateClientToken();
- failReason = needLoginAgain;
- }
- else failReason = failReasonNew;
- }
- }
- switch (m_session->status)
- {
- case AuthSession::Undetermined: {
- qCritical() << "Received undetermined session status during login. Bye.";
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
- return;
- }
- case AuthSession::RequiresPassword: {
- // FIXME: this needs to understand MSA
- EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
- auto username = m_session->username;
- auto chopN = [](QString toChop, int N) -> QString
- {
- if(toChop.size() > N)
- {
- auto left = toChop.left(N);
- left += QString("\u25CF").repeated(toChop.size() - N);
- return left;
- }
- return toChop;
- };
+ m_accountToUse->fillSession(m_session);
- if(username.contains('@'))
- {
- auto parts = username.split('@');
- auto mailbox = chopN(parts[0],3);
- QString domain = chopN(parts[1], 3);
- username = mailbox + '@' + domain;
- }
- passDialog.setUsername(username);
- if (passDialog.exec() == QDialog::Accepted)
+ switch(m_accountToUse->accountState()) {
+ case AccountState::Offline: {
+ // we ask the user for a player name
+ bool ok = false;
+ QString usedname = m_session->player_name;
+ QString name = QInputDialog::getText(
+ m_parentWidget,
+ tr("Player name"),
+ tr("Choose your offline mode player name."),
+ QLineEdit::Normal,
+ m_session->player_name,
+ &ok
+ );
+ if (!ok)
{
- password = passDialog.password();
+ tryagain = false;
+ break;
}
- else
+ if (name.length())
{
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
+ usedname = name;
}
- break;
+ m_session->MakeOffline(usedname);
+ // offline flavored game from here :3
+ // NOTE: fallthrough is intentional
}
- case AuthSession::RequiresProfileSetup: {
- auto entitlement = m_accountToUse->accountData()->minecraftEntitlement;
- QString errorString;
- if(!entitlement.canPlayMinecraft) {
- errorString = tr("The account does not own Minecraft. You need to purchase the game first to play it.");
- QMessageBox::warning(
- nullptr,
- tr("Missing Minecraft profile"),
- errorString,
- QMessageBox::StandardButton::Ok,
- QMessageBox::StandardButton::Ok
- );
- tryagain = false;
- emitFailed(errorString);
- return;
+ case AccountState::Online: {
+ if(m_accountToUse->ownsMinecraft() && !m_accountToUse->hasProfile()) {
+ auto entitlement = m_accountToUse->accountData()->minecraftEntitlement;
+ QString errorString;
+ if(!entitlement.canPlayMinecraft) {
+ errorString = tr("The account does not own Minecraft. You need to purchase the game first to play it.");
+ QMessageBox::warning(
+ nullptr,
+ tr("Missing Minecraft profile"),
+ errorString,
+ QMessageBox::StandardButton::Ok,
+ QMessageBox::StandardButton::Ok
+ );
+ emitFailed(errorString);
+ return;
+ }
+ // Now handle setting up a profile name here...
+ ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
+ if (dialog.exec() == QDialog::Accepted)
+ {
+ tryagain = true;
+ continue;
+ }
+ else
+ {
+ emitFailed(tr("Received undetermined session status during login."));
+ return;
+ }
}
- // Now handle setting up a profile name here...
- ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
- if (dialog.exec() == QDialog::Accepted)
- {
- tryagain = true;
- continue;
+ else {
+ launchInstance();
}
- else
+ return;
+ }
+ case AccountState::Unchecked: {
+ m_accountToUse->refresh();
+ // NOTE: fallthrough intentional
+ }
+ case AccountState::Working: {
+ // refresh is in progress, we need to wait for it to finish to proceed.
+ ProgressDialog progDialog(m_parentWidget);
+ if (m_online)
{
- tryagain = false;
- emitFailed(tr("Received undetermined session status during login."));
- return;
+ progDialog.setSkipButton(true, tr("Play Offline"));
}
+ auto task = m_accountToUse->currentTask();
+ progDialog.execWithTask(task.get());
+ continue;
+ }
+ // FIXME: this is missing - the meaning is that the account is queued for refresh and we should wait for that
+ /*
+ case AccountState::Queued: {
+ return;
}
- case AuthSession::RequiresOAuth: {
- auto errorString = tr("Microsoft account has expired and needs to be logged into manually again.");
+ */
+ case AccountState::Errored: {
+ // This means some sort of soft error that we can fix with a refresh ... so let's refresh.
+ // TODO: implement
+ return;
+ }
+ case AccountState::Expired: {
+ auto errorString = tr("The account has expired and needs to be logged into manually again.");
QMessageBox::warning(
m_parentWidget,
- tr("Microsoft Account refresh failed"),
+ tr("Account refresh failed"),
errorString,
QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok
);
- tryagain = false;
emitFailed(errorString);
return;
}
- case AuthSession::GoneOrMigrated: {
+ case AccountState::Gone: {
auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to.");
QMessageBox::warning(
m_parentWidget,
@@ -235,40 +222,9 @@ void LaunchController::login() {
QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok
);
- tryagain = false;
emitFailed(errorString);
return;
}
- case AuthSession::PlayableOffline: {
- // we ask the user for a player name
- bool ok = false;
- QString usedname = m_session->player_name;
- QString name = QInputDialog::getText(
- m_parentWidget,
- tr("Player name"),
- tr("Choose your offline mode player name."),
- QLineEdit::Normal,
- m_session->player_name,
- &ok
- );
- if (!ok)
- {
- tryagain = false;
- break;
- }
- if (name.length())
- {
- usedname = name;
- }
- m_session->MakeOffline(usedname);
- // offline flavored game from here :3
- }
- case AuthSession::PlayableOnline:
- {
- launchInstance();
- tryagain = false;
- return;
- }
}
}
emitFailed(tr("Failed to launch."));
@@ -334,14 +290,7 @@ void LaunchController::launchInstance()
online_mode = "offline";
}
- QString auth_server_status;
- if(m_session->auth_server_online) {
- auth_server_status = "online";
- } else {
- auth_server_status = "offline";
- }
-
- m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\nAuthentication server is " + auth_server_status + "\n", MessageLevel::Launcher));
+ m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
// Prepend Version
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h
index 09cd2c73..fa42747e 100644
--- a/launcher/minecraft/auth/AccountData.h
+++ b/launcher/minecraft/auth/AccountData.h
@@ -41,6 +41,16 @@ enum class AccountType {
Mojang
};
+enum class AccountState {
+ Unchecked,
+ Offline,
+ Working,
+ Online,
+ Errored,
+ Expired,
+ Gone
+};
+
struct AccountData {
QJsonObject saveState() const;
bool resumeStateFromV2(QJsonObject data);
@@ -77,4 +87,9 @@ struct AccountData {
MinecraftProfile minecraftProfile;
MinecraftEntitlement minecraftEntitlement;
Katabasis::Validity validity_ = Katabasis::Validity::None;
+
+ // runtime only information (not saved with the account)
+ QString internalId;
+ QString errorString;
+ AccountState accountState = AccountState::Unchecked;
};
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index d7537345..c44e3e89 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -15,6 +15,7 @@
#include "AccountList.h"
#include "AccountData.h"
+#include "AccountTask.h"
#include <QIODevice>
#include <QFile>
@@ -24,6 +25,7 @@
#include <QJsonObject>
#include <QJsonParseError>
#include <QDir>
+#include <QTimer>