diff options
| author | Petr Mrázek <peterix@gmail.com> | 2021-07-26 21:44:11 +0200 |
|---|---|---|
| committer | Petr Mrázek <peterix@gmail.com> | 2021-08-15 23:18:50 +0200 |
| commit | 3a53349e332599221bc325f7fac9dc7927194bc2 (patch) | |
| tree | 2ee40fa6044c241b3b7db27fe0b83931b453c2b2 | |
| parent | fca2e9e44cb44004eec7f47c03b186bd5e44dc32 (diff) | |
| download | PrismLauncher-3a53349e332599221bc325f7fac9dc7927194bc2.tar.gz PrismLauncher-3a53349e332599221bc325f7fac9dc7927194bc2.tar.bz2 PrismLauncher-3a53349e332599221bc325f7fac9dc7927194bc2.zip | |
GH-3392 dirty initial MSA support that shares logic with Mojang flows
Both act as the first step of AuthContext.
66 files changed, 2332 insertions, 2467 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 521fdaad..817b4cfc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,9 @@ set(MultiMC_DISCORD_URL "" CACHE STRING "URL for the Discord guild.") # Subreddit URL set(MultiMC_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.") +# MSA Client ID +set(MultiMC_MSA_CLIENT_ID "" CACHE STRING "Client ID used for MSA authentication") + #### Check the current Git commit and branch include(GetGitRevisionDescription) get_git_head_revision(MultiMC_GIT_REFSPEC MultiMC_GIT_COMMIT) diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in index 60d417a6..9d4771b4 100644 --- a/buildconfig/BuildConfig.cpp.in +++ b/buildconfig/BuildConfig.cpp.in @@ -35,6 +35,7 @@ Config::Config() PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@"; IMGUR_CLIENT_ID = "@MultiMC_IMGUR_CLIENT_ID@"; META_URL = "@MultiMC_META_URL@"; + MSA_CLIENT_ID = "@MultiMC_MSA_CLIENT_ID@"; BUG_TRACKER_URL = "@MultiMC_BUG_TRACKER_URL@"; DISCORD_URL = "@MultiMC_DISCORD_URL@"; diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 185bebad..71880109 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -75,13 +75,17 @@ public: */ QString META_URL; + /** + * MSA client ID - registered with Azure / Microsoft, needs correct setup on MS side. + */ + QString MSA_CLIENT_ID; + QString BUG_TRACKER_URL; QString DISCORD_URL; QString SUBREDDIT_URL; QString RESOURCE_BASE = "https://resources.download.minecraft.net/"; QString LIBRARY_BASE = "https://libraries.minecraft.net/"; - QString SKINS_BASE = "https://crafatar.com/skins/"; QString AUTH_BASE = "https://authserver.mojang.com/"; QString MOJANG_STATUS_URL = "https://status.mojang.com/check"; QString IMGUR_BASE_URL = "https://api.imgur.com/3/"; diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h index 833646c0..8c08dc05 100644 --- a/launcher/BaseInstance.h +++ b/launcher/BaseInstance.h @@ -26,7 +26,7 @@ #include "settings/INIFile.h" #include "BaseVersionList.h" -#include "minecraft/auth/MojangAccount.h" +#include "minecraft/auth/MinecraftAccount.h" #include "MessageLevel.h" #include "pathmatcher/IPathMatcher.h" diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 37f5d3a1..3c140ede 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -203,20 +203,31 @@ set(STATUS_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/AccountTask.cpp minecraft/auth/AuthSession.h minecraft/auth/AuthSession.cpp - minecraft/auth/MojangAccountList.h - minecraft/auth/MojangAccountList.cpp - minecraft/auth/MojangAccount.h - minecraft/auth/MojangAccount.cpp - minecraft/auth/YggdrasilTask.h - minecraft/auth/YggdrasilTask.cpp - minecraft/auth/flows/AuthenticateTask.h - minecraft/auth/flows/AuthenticateTask.cpp - minecraft/auth/flows/RefreshTask.cpp - minecraft/auth/flows/RefreshTask.cpp - minecraft/auth/flows/ValidateTask.h - minecraft/auth/flows/ValidateTask.cpp + minecraft/auth/AccountList.h + minecraft/auth/AccountList.cpp + minecraft/auth/MinecraftAccount.h + minecraft/auth/MinecraftAccount.cpp + minecraft/auth/flows/AuthContext.h + minecraft/auth/flows/AuthContext.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/gameoptions/GameOptions.h minecraft/gameoptions/GameOptions.cpp @@ -732,6 +743,8 @@ SET(MULTIMC_SOURCES dialogs/IconPickerDialog.h dialogs/LoginDialog.cpp dialogs/LoginDialog.h + dialogs/MSALoginDialog.cpp + dialogs/MSALoginDialog.h dialogs/NewComponentDialog.cpp dialogs/NewComponentDialog.h dialogs/NewInstanceDialog.cpp @@ -850,6 +863,7 @@ SET(MULTIMC_UIS dialogs/EditAccountDialog.ui dialogs/ExportInstanceDialog.ui dialogs/LoginDialog.ui + dialogs/MSALoginDialog.ui dialogs/UpdateDialog.ui dialogs/NotificationDialog.ui dialogs/SkinUploadDialog.ui @@ -892,6 +906,7 @@ target_link_libraries(MultiMC_logic optional-bare tomlc99 BuildConfig + Katabasis ) target_link_libraries(MultiMC_logic Qt5::Core diff --git a/launcher/Env.cpp b/launcher/Env.cpp index 71b49d95..abf9f58c 100644 --- a/launcher/Env.cpp +++ b/launcher/Env.cpp @@ -101,7 +101,6 @@ void Env::initHttpMetaCache() m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath()); m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath()); m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath()); - m_metacache->addBase("skins", QDir("accounts/skins").absolutePath()); m_metacache->addBase("root", QDir::currentPath()); m_metacache->addBase("translations", QDir("translations").absolutePath()); m_metacache->addBase("icons", QDir("cache/icons").absolutePath()); diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index ee764082..11780625 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -1,6 +1,6 @@ #include "LaunchController.h" #include "MainWindow.h" -#include <minecraft/auth/MojangAccountList.h> +#include <minecraft/auth/AccountList.h> #include "MultiMC.h" #include "dialogs/CustomMessageBox.h" #include "dialogs/ProfileSelectDialog.h" @@ -12,7 +12,7 @@ #include <QLineEdit> #include <QInputDialog> #include <tasks/Task.h> -#include <minecraft/auth/YggdrasilTask.h> +#include <minecraft/auth/AccountTask.h> #include <launch/steps/TextPrint.h> #include <QStringList> #include <QHostInfo> @@ -35,22 +35,23 @@ void LaunchController::executeTask() } // FIXME: minecraft specific -void LaunchController::login() -{ +void LaunchController::login() { JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget); // Find an account to use. - std::shared_ptr<MojangAccountList> accounts = MMC->accounts(); - MojangAccountPtr account = accounts->activeAccount(); + std::shared_ptr<AccountList> accounts = MMC->accounts(); if (accounts->count() <= 0) { // Tell the user they need to log in at least one account in order to play. auto reply = CustomMessageBox::selectable( - m_parentWidget, tr("No Accounts"), + m_parentWidget, + tr("No Accounts"), tr("In order to play Minecraft, you must have at least one Mojang or Minecraft " "account logged in to MultiMC." "Would you like to open the account manager to add an account now?"), - QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec(); + QMessageBox::Information, + QMessageBox::Yes | QMessageBox::No + )->exec(); if (reply == QMessageBox::Yes) { @@ -58,11 +59,16 @@ void LaunchController::login() MMC->ShowGlobalSettings(m_parentWidget, "accounts"); } } - else if (account.get() == nullptr) + + MinecraftAccountPtr account = accounts->activeAccount(); + if (account.get() == nullptr) { // If no default account is set, ask the user which one to use. - ProfileSelectDialog selectDialog(tr("Which profile would you like to use?"), - ProfileSelectDialog::GlobalDefaultCheckbox, m_parentWidget); + ProfileSelectDialog selectDialog( + tr("Which account would you like to use?"), + ProfileSelectDialog::GlobalDefaultCheckbox, + m_parentWidget + ); selectDialog.exec(); @@ -70,8 +76,9 @@ void LaunchController::login() account = selectDialog.selectedAccount(); // If the user said to use the account as default, do that. - if (selectDialog.useAsGlobalDefault() && account.get() != nullptr) - accounts->setActiveAccount(account->username()); + if (selectDialog.useAsGlobalDefault() && account.get() != nullptr) { + accounts->setActiveAccount(account->profileId()); + } } // if no account is selected, we bail @@ -93,7 +100,13 @@ void LaunchController::login() { m_session = std::make_shared<AuthSession>(); m_session->wants_online = m_online; - auto task = account->login(m_session, password); + std::shared_ptr<AccountTask> task; + if(!password.isNull()) { + task = account->login(m_session, password); + } + else { + task = account->refresh(m_session); + } if (task) { // We'll need to validate the access token to make sure the account @@ -107,9 +120,9 @@ void LaunchController::login() if (!task->wasSuccessful()) { auto failReasonNew = task->failReason(); - if(failReasonNew == "Invalid token.") + if(failReasonNew == "Invalid token." || failReasonNew == "Invalid Signature") { - account->invalidateClientToken(); + // account->invalidateClientToken(); failReason = needLoginAgain; } else failReason = failReasonNew; @@ -117,72 +130,82 @@ void LaunchController::login() } 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.")); - break; - } - case AuthSession::RequiresPassword: - { - EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField); - auto username = m_session->username; - auto chopN = [](QString toChop, int N) -> QString - { - if(toChop.size() > N) + 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 { - auto left = toChop.left(N); - left += QString("\u25CF").repeated(toChop.size() - N); - return left; - } - return toChop; - }; + if(toChop.size() > N) + { + auto left = toChop.left(N); + left += QString("\u25CF").repeated(toChop.size() - N); + return left; + } + return toChop; + }; - 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) - { - password = passDialog.password(); + 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) + { + password = passDialog.password(); + } + else + { + tryagain = false; + emitFailed(tr("Received undetermined session status during login.")); + } + break; } - else - { + case AuthSession::RequiresOAuth: { + // FIXME: add UI for expired / broken MS accounts tryagain = false; + emitFailed(tr("Microsoft account has expired and needs to be logged into again.")); + return; } - break; - } - 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; + 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 } - if (name.length()) + case AuthSession::PlayableOnline: { - usedname = name; + launchInstance(); + tryagain = false; + return; } - m_session->MakeOffline(usedname); - // offline flavored game from here :3 - } - case AuthSession::PlayableOnline: - { - launchInstance(); - tryagain = false; - return; - } } } emitFailed(tr("Failed to launch.")); diff --git a/launcher/MainWindow.cpp b/launcher/MainWindow.cpp index 9225193e..182b22e9 100644 --- a/launcher/MainWindow.cpp +++ b/launcher/MainWindow.cpp @@ -54,7 +54,7 @@ #include <java/JavaUtils.h> #include <java/JavaInstallList.h> #include <launch/LaunchTask.h> -#include <minecraft/auth/MojangAccountList.h> +#include <minecraft/auth/AccountList.h> #include <SkinUtils.h> #include <BuildConfig.h> #include <net/NetJob.h> @@ -90,6 +90,20 @@ #include "KonamiCode.h" #include <InstanceCopyTask.h> +namespace { +QString profileInUseFilter(const QString & profile, bool used) +{ + if(used) + { + return QObject::tr("%1 (in use)").arg(profile); + } + else + { + return profile; + } +} +} + // WHY: to hold the pre-translation strings together with the T pointer, so it can be retranslated without a lot of ugly code template <typename T> class Translated @@ -753,49 +767,27 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow // Update the menu when the active account changes. // Shouldn't have to use lambdas here like this, but if I don't, the compiler throws a fit. // Template hell sucks... - connect(MMC->accounts().get(), &MojangAccountList::activeAccountChanged, [this] - { - activeAccountChanged(); - }); - connect(MMC->accounts().get(), &MojangAccountList::listChanged, [this] - { - repopulateAccountsMenu(); - }); + connect( + MMC->accounts().get(), + &AccountList::activeAccountChanged, + [this] { + activeAccountChanged(); + } + ); + connect( + MMC->accounts().get(), + &AccountList::listChanged, + [this] + { + repopulateAccountsMenu(); + } + ); // Show initial account activeAccountChanged(); - auto accounts = MMC->accounts(); - - QList<Net::Download::Ptr> skin_dls; |
