diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:45:07 +0300 |
| commit | 31b9a8949ed0a288143e23bf739f2eb64fdc63be (patch) | |
| tree | 8a984fa143c38fccad461a77792d6864f3e82cd3 /meshmc/launcher/minecraft/auth/steps/MSAStep.cpp | |
| parent | 934382c8a1ce738589dee9ee0f14e1cec812770e (diff) | |
| parent | fad6a1066616b69d7f5fef01178efdf014c59537 (diff) | |
| download | Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.tar.gz Project-Tick-31b9a8949ed0a288143e23bf739f2eb64fdc63be.zip | |
Add 'meshmc/' from commit 'fad6a1066616b69d7f5fef01178efdf014c59537'
git-subtree-dir: meshmc
git-subtree-mainline: 934382c8a1ce738589dee9ee0f14e1cec812770e
git-subtree-split: fad6a1066616b69d7f5fef01178efdf014c59537
Diffstat (limited to 'meshmc/launcher/minecraft/auth/steps/MSAStep.cpp')
| -rw-r--r-- | meshmc/launcher/minecraft/auth/steps/MSAStep.cpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/meshmc/launcher/minecraft/auth/steps/MSAStep.cpp b/meshmc/launcher/minecraft/auth/steps/MSAStep.cpp new file mode 100644 index 0000000000..9be4761549 --- /dev/null +++ b/meshmc/launcher/minecraft/auth/steps/MSAStep.cpp @@ -0,0 +1,161 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "MSAStep.h" + +#include <QNetworkRequest> +#include <QDesktopServices> + +#include "minecraft/auth/AuthRequest.h" +#include "minecraft/auth/Parsers.h" + +#include "Application.h" + +MSAStep::MSAStep(AccountData* data, Action action) + : AuthStep(data), m_action(action) +{ + m_replyHandler = new QOAuthHttpServerReplyHandler(this); + m_replyHandler->setCallbackText( + tr("Login successful! You can close this page and return to MeshMC.")); + + m_oauth2 = new QOAuth2AuthorizationCodeFlow(this); + m_oauth2->setClientIdentifier(APPLICATION->msaClientId()); + m_oauth2->setAuthorizationUrl(QUrl( + "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize")); + m_oauth2->setTokenUrl( + QUrl("https://login.microsoftonline.com/consumers/oauth2/v2.0/token")); + m_oauth2->setScope("XboxLive.signin offline_access"); + m_oauth2->setReplyHandler(m_replyHandler); + m_oauth2->setNetworkAccessManager(APPLICATION->network().get()); + + connect(m_oauth2, &QOAuth2AuthorizationCodeFlow::granted, this, + &MSAStep::onGranted); + connect(m_oauth2, &QOAuth2AuthorizationCodeFlow::requestFailed, this, + &MSAStep::onRequestFailed); + connect(m_oauth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, + &MSAStep::onOpenBrowser); +} + +MSAStep::~MSAStep() noexcept = default; + +QString MSAStep::describe() +{ + return tr("Logging in with Microsoft account."); +} + +void MSAStep::rehydrate() +{ + switch (m_action) { + case Refresh: { + // TODO: check the tokens and see if they are old (older than a day) + return; + } + case Login: { + // NOOP + return; + } + } +} + +void MSAStep::perform() +{ + switch (m_action) { + case Refresh: { + // Load the refresh token from stored account data + m_oauth2->setRefreshToken(m_data->msaToken.refresh_token); + m_oauth2->refreshTokens(); + return; + } + case Login: { + *m_data = AccountData(); + if (!m_replyHandler->isListening()) { + if (!m_replyHandler->listen(QHostAddress::LocalHost)) { + emit finished(AccountTaskState::STATE_FAILED_HARD, + tr("Failed to start local HTTP server for " + "OAuth2 callback.")); + return; + } + } + m_oauth2->setModifyParametersFunction( + [](QAbstractOAuth::Stage stage, + QMultiMap<QString, QVariant>* parameters) { + if (stage == + QAbstractOAuth::Stage::RequestingAuthorization) { + parameters->insert("prompt", "select_account"); + } + }); + m_oauth2->grant(); + return; + } + } +} + +void MSAStep::onOpenBrowser(const QUrl& url) +{ + emit authorizeWithBrowser(url); + QDesktopServices::openUrl(url); +} + +void MSAStep::onGranted() +{ + m_replyHandler->close(); + + // Store the tokens in account data + m_data->msaToken.token = m_oauth2->token(); + m_data->msaToken.refresh_token = m_oauth2->refreshToken(); + m_data->msaToken.issueInstant = QDateTime::currentDateTimeUtc(); + m_data->msaToken.notAfter = m_oauth2->expirationAt(); + if (!m_data->msaToken.notAfter.isValid()) { + m_data->msaToken.notAfter = m_data->msaToken.issueInstant.addSecs(3600); + } + m_data->msaToken.validity = Katabasis::Validity::Certain; + + emit finished(AccountTaskState::STATE_WORKING, tr("Got MSA token.")); +} + +void MSAStep::onRequestFailed(QAbstractOAuth::Error error) +{ + m_replyHandler->close(); + + switch (error) { + case QAbstractOAuth::Error::NetworkError: + emit finished( + AccountTaskState::STATE_OFFLINE, + tr("Microsoft authentication failed due to a network error.")); + return; + case QAbstractOAuth::Error::ServerError: + case QAbstractOAuth::Error::OAuthTokenNotFoundError: + case QAbstractOAuth::Error::OAuthTokenSecretNotFoundError: + case QAbstractOAuth::Error::OAuthCallbackNotVerified: + emit finished(AccountTaskState::STATE_FAILED_HARD, + tr("Microsoft authentication failed.")); + return; + case QAbstractOAuth::Error::ExpiredError: + emit finished(AccountTaskState::STATE_FAILED_GONE, + tr("Microsoft authentication token expired.")); + return; + default: + emit finished(AccountTaskState::STATE_FAILED_HARD, + tr("Microsoft authentication failed with an " + "unrecognized error.")); + return; + } +} |
