mirror of
https://github.com/MultiMC/MultiMC5.git
synced 2025-04-17 08:43:29 +00:00
GH-4317 Detect forced migration state and show errors for it
This commit is contained in:
parent
ef1bf57b58
commit
b39410a2c2
@ -224,6 +224,8 @@ set(MINECRAFT_SOURCES
|
||||
|
||||
minecraft/auth/steps/EntitlementsStep.cpp
|
||||
minecraft/auth/steps/EntitlementsStep.h
|
||||
minecraft/auth/steps/ForcedMigrationStep.cpp
|
||||
minecraft/auth/steps/ForcedMigrationStep.h
|
||||
minecraft/auth/steps/GetSkinStep.cpp
|
||||
minecraft/auth/steps/GetSkinStep.h
|
||||
minecraft/auth/steps/LauncherLoginStep.cpp
|
||||
|
@ -239,6 +239,18 @@ void LaunchController::login() {
|
||||
emitFailed(errorString);
|
||||
return;
|
||||
}
|
||||
case AccountState::MustMigrate: {
|
||||
auto errorString = tr("The account must be migrated to a Microsoft account.");
|
||||
QMessageBox::warning(
|
||||
m_parentWidget,
|
||||
tr("Account requires migration"),
|
||||
errorString,
|
||||
QMessageBox::StandardButton::Ok,
|
||||
QMessageBox::StandardButton::Ok
|
||||
);
|
||||
emitFailed(errorString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
emitFailed(tr("Failed to launch."));
|
||||
|
@ -322,6 +322,7 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
|
||||
if(type == AccountType::Mojang) {
|
||||
legacy = data.value("legacy").toBool(false);
|
||||
canMigrateToMSA = data.value("canMigrateToMSA").toBool(false);
|
||||
mustMigrateToMSA = data.value("mustMigrateToMSA").toBool(false);
|
||||
}
|
||||
|
||||
if(type == AccountType::MSA) {
|
||||
@ -355,6 +356,9 @@ QJsonObject AccountData::saveState() const {
|
||||
if(canMigrateToMSA) {
|
||||
output["canMigrateToMSA"] = true;
|
||||
}
|
||||
if(mustMigrateToMSA) {
|
||||
output["mustMigrateToMSA"] = true;
|
||||
}
|
||||
}
|
||||
else if (type == AccountType::MSA) {
|
||||
output["type"] = "MSA";
|
||||
|
@ -48,7 +48,8 @@ enum class AccountState {
|
||||
Online,
|
||||
Errored,
|
||||
Expired,
|
||||
Gone
|
||||
Gone,
|
||||
MustMigrate
|
||||
};
|
||||
|
||||
struct AccountData {
|
||||
@ -79,6 +80,7 @@ struct AccountData {
|
||||
AccountType type = AccountType::MSA;
|
||||
bool legacy = false;
|
||||
bool canMigrateToMSA = false;
|
||||
bool mustMigrateToMSA = false;
|
||||
|
||||
Katabasis::Token msaToken;
|
||||
Katabasis::Token userToken;
|
||||
|
@ -294,6 +294,9 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
|
||||
case AccountState::Gone: {
|
||||
return tr("Gone", "Account status");
|
||||
}
|
||||
case AccountState::MustMigrate: {
|
||||
return tr("Must Migrate", "Account status");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@ QString AccountTask::getStateMessage() const
|
||||
return tr("Failed to contact the authentication server.");
|
||||
case AccountTaskState::STATE_FAILED_SOFT:
|
||||
return tr("Encountered an error during authentication.");
|
||||
case AccountTaskState::STATE_FAILED_MUST_MIGRATE:
|
||||
return tr("Failed to authenticate. The account must be migrated to a Microsoft account to be usable.");
|
||||
case AccountTaskState::STATE_FAILED_HARD:
|
||||
return tr("Failed to authenticate. The session has expired.");
|
||||
case AccountTaskState::STATE_FAILED_GONE:
|
||||
@ -84,6 +86,12 @@ bool AccountTask::changeState(AccountTaskState newState, QString reason)
|
||||
emitFailed(reason);
|
||||
return false;
|
||||
}
|
||||
case AccountTaskState::STATE_FAILED_MUST_MIGRATE: {
|
||||
m_data->errorString = reason;
|
||||
m_data->accountState = AccountState::MustMigrate;
|
||||
emitFailed(reason);
|
||||
return false;
|
||||
}
|
||||
case AccountTaskState::STATE_FAILED_HARD: {
|
||||
m_data->errorString = reason;
|
||||
m_data->accountState = AccountState::Expired;
|
||||
|
@ -36,6 +36,7 @@ enum class AccountTaskState
|
||||
STATE_WORKING,
|
||||
STATE_SUCCEEDED,
|
||||
STATE_FAILED_SOFT, //!< soft failure. authentication went through partially
|
||||
STATE_FAILED_MUST_MIGRATE, //!< soft failure. main tokens are valid, but the account must be migrated
|
||||
STATE_FAILED_HARD, //!< hard failure. main tokens are invalid
|
||||
STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists
|
||||
STATE_OFFLINE //!< soft failure. authentication failed in the first step in a 'soft' way
|
||||
|
@ -145,6 +145,7 @@ void MinecraftAccount::authFailed(QString reason)
|
||||
{
|
||||
switch (m_currentTask->taskState()) {
|
||||
case AccountTaskState::STATE_OFFLINE:
|
||||
case AccountTaskState::STATE_FAILED_MUST_MIGRATE:
|
||||
case AccountTaskState::STATE_FAILED_SOFT: {
|
||||
// NOTE: this doesn't do much. There was an error of some sort.
|
||||
}
|
||||
|
@ -247,6 +247,36 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseForcedMigrationResponse(QByteArray & data, bool& result) {
|
||||
qDebug() << "Parsing Rollout response...";
|
||||
#ifndef NDEBUG
|
||||
qDebug() << data;
|
||||
#endif
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if(jsonError.error) {
|
||||
qWarning() << "Failed to parse response from https://api.minecraftservices.com/rollout/v1/msamigrationforced as JSON: " << jsonError.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto obj = doc.object();
|
||||
QString feature;
|
||||
if(!getString(obj.value("feature"), feature)) {
|
||||
qWarning() << "Rollout feature is not a string";
|
||||
return false;
|
||||
}
|
||||
if(feature != "msamigrationforced") {
|
||||
qWarning() << "Rollout feature is not what we expected (msamigrationforced), but is instead \"" << feature << "\"";
|
||||
return false;
|
||||
}
|
||||
if(!getBool(obj.value("rollout"), result)) {
|
||||
qWarning() << "Rollout feature is not a string";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseRolloutResponse(QByteArray & data, bool& result) {
|
||||
qDebug() << "Parsing Rollout response...";
|
||||
#ifndef NDEBUG
|
||||
|
@ -16,4 +16,5 @@ namespace Parsers
|
||||
bool parseMinecraftProfile(QByteArray &data, MinecraftProfile &output);
|
||||
bool parseMinecraftEntitlements(QByteArray &data, MinecraftEntitlement &output);
|
||||
bool parseRolloutResponse(QByteArray &data, bool& result);
|
||||
bool parseForcedMigrationResponse(QByteArray & data, bool& result);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "minecraft/auth/steps/YggdrasilStep.h"
|
||||
#include "minecraft/auth/steps/MinecraftProfileStep.h"
|
||||
#include "minecraft/auth/steps/ForcedMigrationStep.h"
|
||||
#include "minecraft/auth/steps/MigrationEligibilityStep.h"
|
||||
#include "minecraft/auth/steps/GetSkinStep.h"
|
||||
|
||||
@ -10,6 +11,7 @@ MojangRefresh::MojangRefresh(
|
||||
QObject *parent
|
||||
) : AuthFlow(data, parent) {
|
||||
m_steps.append(new YggdrasilStep(m_data, QString()));
|
||||
m_steps.append(new ForcedMigrationStep(m_data));
|
||||
m_steps.append(new MinecraftProfileStep(m_data));
|
||||
m_steps.append(new MigrationEligibilityStep(m_data));
|
||||
m_steps.append(new GetSkinStep(m_data));
|
||||
@ -21,6 +23,7 @@ MojangLogin::MojangLogin(
|
||||
QObject *parent
|
||||
): AuthFlow(data, parent), m_password(password) {
|
||||
m_steps.append(new YggdrasilStep(m_data, m_password));
|
||||
m_steps.append(new ForcedMigrationStep(m_data));
|
||||
m_steps.append(new MinecraftProfileStep(m_data));
|
||||
m_steps.append(new MigrationEligibilityStep(m_data));
|
||||
m_steps.append(new GetSkinStep(m_data));
|
||||
|
52
launcher/minecraft/auth/steps/ForcedMigrationStep.cpp
Normal file
52
launcher/minecraft/auth/steps/ForcedMigrationStep.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include "ForcedMigrationStep.h"
|
||||
|
||||
#include <QNetworkRequest>
|
||||
|
||||
#include "minecraft/auth/AuthRequest.h"
|
||||
#include "minecraft/auth/Parsers.h"
|
||||
|
||||
ForcedMigrationStep::ForcedMigrationStep(AccountData* data) : AuthStep(data) {
|
||||
|
||||
}
|
||||
|
||||
ForcedMigrationStep::~ForcedMigrationStep() noexcept = default;
|
||||
|
||||
QString ForcedMigrationStep::describe() {
|
||||
return tr("Checking for migration eligibility.");
|
||||
}
|
||||
|
||||
void ForcedMigrationStep::perform() {
|
||||
auto url = QUrl("https://api.minecraftservices.com/rollout/v1/msamigrationforced");
|
||||
QNetworkRequest request = QNetworkRequest(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
|
||||
|
||||
AuthRequest *requestor = new AuthRequest(this);
|
||||
connect(requestor, &AuthRequest::finished, this, &ForcedMigrationStep::onRequestDone);
|
||||
requestor->get(request);
|
||||
}
|
||||
|
||||
void ForcedMigrationStep::rehydrate() {
|
||||
// NOOP, for now. We only save bools and there's nothing to check.
|
||||
}
|
||||
|
||||
void ForcedMigrationStep::onRequestDone(
|
||||
QNetworkReply::NetworkError error,
|
||||
QByteArray data,
|
||||
QList<QNetworkReply::RawHeaderPair> headers
|
||||
) {
|
||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||
requestor->deleteLater();
|
||||
|
||||
if (error == QNetworkReply::NoError) {
|
||||
Parsers::parseForcedMigrationResponse(data, m_data->mustMigrateToMSA);
|
||||
}
|
||||
if(m_data->mustMigrateToMSA) {
|
||||
emit finished(AccountTaskState::STATE_FAILED_MUST_MIGRATE, tr("The account must be migrated to a Microsoft account."));
|
||||
}
|
||||
else {
|
||||
emit finished(AccountTaskState::STATE_WORKING, tr("Got forced migration flags"));
|
||||
}
|
||||
|
||||
}
|
||||
|
23
launcher/minecraft/auth/steps/ForcedMigrationStep.h
Normal file
23
launcher/minecraft/auth/steps/ForcedMigrationStep.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
#include "minecraft/auth/AuthStep.h"
|
||||
|
||||
|
||||
class ForcedMigrationStep : public AuthStep {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ForcedMigrationStep(AccountData *data);
|
||||
virtual ~ForcedMigrationStep() noexcept;
|
||||
|
||||
void perform() override;
|
||||
void rehydrate() override;
|
||||
|
||||
QString describe() override;
|
||||
|
||||
private slots:
|
||||
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user