GH-3392 Add recognition of already migrated Mojang accounts

This commit is contained in:
Petr Mrázek 2021-08-29 19:58:35 +02:00
parent 1e1655bc4b
commit 7239502675
6 changed files with 97 additions and 41 deletions

View File

@ -183,6 +183,19 @@ void LaunchController::login() {
emitFailed(errorString);
return;
}
case AuthSession::GoneOrMigrated: {
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(
nullptr,
tr("Account gone"),
errorString,
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;

View File

@ -49,6 +49,8 @@ QString AccountTask::getStateMessage() const
return tr("Failed to contact the authentication server.");
case STATE_FAILED_HARD:
return tr("Failed to authenticate.");
case STATE_FAILED_GONE:
return tr("Failed to authenticate. The account no longer exists.");
default:
return tr("...");
}
@ -62,7 +64,7 @@ void AccountTask::changeState(AccountTask::State newState, QString reason)
{
emitSucceeded();
}
else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT)
else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT || newState == STATE_FAILED_GONE)
{
emitFailed(reason);
}

View File

@ -76,6 +76,7 @@ public:
STATE_WORKING,
STATE_FAILED_SOFT, //!< soft failure. this generally means the user auth details haven't been invalidated
STATE_FAILED_HARD, //!< hard failure. auth is invalid
STATE_FAILED_GONE, //!< hard failure. auth is invalid, and the account no longer exists
STATE_SUCCEEDED
} m_accountState = STATE_CREATED;

View File

@ -18,7 +18,8 @@ struct AuthSession
RequiresOAuth,
RequiresPassword,
PlayableOffline,
PlayableOnline
PlayableOnline,
GoneOrMigrated
} status = Undetermined;
// client token

View File

@ -227,18 +227,28 @@ void MinecraftAccount::authFailed(QString reason)
auto session = m_currentTask->getAssignedSession();
// This is emitted when the yggdrasil tasks time out or are cancelled.
// -> we treat the error as no-op
if (m_currentTask->accountState() == AccountTask::STATE_FAILED_SOFT)
{
switch (m_currentTask->accountState()) {
case AccountTask::STATE_FAILED_SOFT: {
if (session)
{
session->status = accountStatus() == Verified ? AuthSession::PlayableOffline : AuthSession::RequiresPassword;
if(accountStatus() == Verified) {
session->status = AuthSession::PlayableOffline;
}
else {
if(data.type == AccountType::MSA) {
session->status = AuthSession::RequiresOAuth;
}
else {
session->status = AuthSession::RequiresPassword;
}
}
session->auth_server_online = false;
fillSession(session);
}
}
else
{
// FIXME: MSA ...
break;
case AccountTask::STATE_FAILED_HARD: {
// FIXME: MSA data clearing
data.yggdrasilToken.token = QString();
data.yggdrasilToken.validity = Katabasis::Validity::None;
data.validity_ = Katabasis::Validity::None;
@ -255,6 +265,24 @@ void MinecraftAccount::authFailed(QString reason)
fillSession(session);
}
}
break;
case AccountTask::STATE_FAILED_GONE: {
data.validity_ = Katabasis::Validity::None;
emit changed();
if (session)
{
session->status = AuthSession::GoneOrMigrated;
session->auth_server_online = true;
fillSession(session);
}
}
break;
case AccountTask::STATE_CREATED:
case AccountTask::STATE_WORKING:
case AccountTask::STATE_SUCCEEDED: {
// Not reachable here, as they are not failures.
}
}
m_currentTask.reset();
}

View File

@ -255,10 +255,17 @@ void Yggdrasil::processReply()
case QNetworkReply::ContentAccessDenied:
case QNetworkReply::ContentOperationNotPermittedError:
break;
case QNetworkReply::ContentGoneError: {
changeState(
STATE_FAILED_GONE,
tr("The Mojang account no longer exists. It may have been migrated to a Microsoft account.")
);
}
default:
changeState(STATE_FAILED_SOFT,
tr("Authentication operation failed due to a network error: %1 (%2)")
.arg(m_netReply->errorString()).arg(m_netReply->error()));
changeState(
STATE_FAILED_SOFT,
tr("Authentication operation failed due to a network error: %1 (%2)").arg(m_netReply->errorString()).arg(m_netReply->error())
);
return;
}
@ -283,10 +290,10 @@ void Yggdrasil::processReply()
}
else
{
changeState(STATE_FAILED_SOFT, tr("Failed to parse authentication server response "
"JSON response: %1 at offset %2.")
.arg(jsonError.errorString())
.arg(jsonError.offset));
changeState(
STATE_FAILED_SOFT,
tr("Failed to parse authentication server response JSON response: %1 at offset %2.").arg(jsonError.errorString()).arg(jsonError.offset)
);
qCritical() << replyData;
}
return;
@ -301,19 +308,18 @@ void Yggdrasil::processReply()
// 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.
qDebug() << "The request failed, but the server gave us an error message. "
"Processing error.";
qDebug() << "The request failed, but the server gave us an error message. Processing error.";
processError(doc.object());
}
else
{
// The server didn't say anything regarding the error. Give the user an unknown
// error.
qDebug()
<< "The request failed and the server gave no error message. Unknown error.";
changeState(STATE_FAILED_SOFT,
tr("An unknown error occurred when trying to communicate with the "
"authentication server: %1").arg(m_netReply->errorString()));
qDebug() << "The request failed and the server gave no error message. Unknown error.";
changeState(
STATE_FAILED_SOFT,
tr("An unknown error occurred when trying to communicate with the authentication server: %1").arg(m_netReply->errorString())
);
}
}
@ -325,8 +331,13 @@ void Yggdrasil::processError(QJsonObject responseData)
if (errorVal.isString() && errorMessageValue.isString())
{
m_error = std::shared_ptr<Error>(new Error{
errorVal.toString(""), errorMessageValue.toString(""), causeVal.toString("")});
m_error = std::shared_ptr<Error>(
new Error {
errorVal.toString(""),
errorMessageValue.toString(""),
causeVal.toString("")
}
);
changeState(STATE_FAILED_HARD, m_error->m_errorMessageVerbose);
}
else