diff options
Diffstat (limited to 'launcher')
-rw-r--r-- | launcher/minecraft/auth/AccountList.cpp | 9 | ||||
-rw-r--r-- | launcher/minecraft/auth/MinecraftAccount.cpp | 24 | ||||
-rw-r--r-- | launcher/minecraft/auth/MinecraftAccount.h | 9 | ||||
-rw-r--r-- | launcher/minecraft/auth/flows/AuthContext.cpp | 109 | ||||
-rw-r--r-- | launcher/minecraft/auth/flows/AuthContext.h | 7 | ||||
-rw-r--r-- | launcher/minecraft/auth/flows/MSAInteractive.cpp | 3 | ||||
-rw-r--r-- | launcher/ui/widgets/VersionListView.cpp | 1 |
7 files changed, 100 insertions, 62 deletions
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index 97ba48f4..d7537345 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -244,8 +244,13 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } case StatusColumn: { - auto isActive = account->isActive(); - return isActive ? "Working" : "Ready"; + if(account->isActive()) { + return tr("Working", "Account status"); + } + if(account->isExpired()) { + return tr("Expired", "Account status"); + } + return tr("Ready", "Account status"); } case ProfileNameColumn: { diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 5cfec49d..30ed6afe 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -34,6 +34,11 @@ #include "flows/MojangRefresh.h" #include "flows/MojangLogin.h" +MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { + m_internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); +} + + MinecraftAccountPtr MinecraftAccount::loadFromJsonV2(const QJsonObject& json) { MinecraftAccountPtr account(new MinecraftAccount()); if(account->data.resumeStateFromV2(json)) { @@ -52,7 +57,7 @@ MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json) { MinecraftAccountPtr MinecraftAccount::createFromUsername(const QString &username) { - MinecraftAccountPtr account(new MinecraftAccount()); + MinecraftAccountPtr account = new MinecraftAccount(); account->data.type = AccountType::Mojang; account->data.yggdrasilToken.extra["userName"] = username; account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); @@ -91,6 +96,23 @@ AccountStatus MinecraftAccount::accountStatus() const { } } +bool MinecraftAccount::isExpired() const { + switch(data.type) { + case AccountType::Mojang: { + return data.accessToken().isEmpty(); + } + break; + case AccountType::MSA: { + return data.msaToken.validity == Katabasis::Validity::None; + } + break; + default: { + return true; + } + } +} + + QPixmap MinecraftAccount::getFace() const { QPixmap skinTexture; if(!skinTexture.loadFromData(data.minecraftProfile.skin.data, "PNG")) { diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 928d3742..459ef903 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -72,7 +72,7 @@ public: /* construction */ explicit MinecraftAccount(const MinecraftAccount &other, QObject *parent) = delete; //! Default constructor - explicit MinecraftAccount(QObject *parent = 0) : QObject(parent) {}; + explicit MinecraftAccount(QObject *parent = 0); static MinecraftAccountPtr createFromUsername(const QString &username); @@ -97,6 +97,10 @@ public: /* manipulation */ shared_qobject_ptr<AccountTask> refresh(AuthSessionPtr session); public: /* queries */ + QString internalId() const { + return m_internalId; + } + QString accountDisplayString() const { return data.accountDisplayString(); } @@ -119,6 +123,8 @@ public: /* queries */ bool isActive() const; + bool isExpired() const; + bool canMigrate() const { return data.canMigrateToMSA; } @@ -168,6 +174,7 @@ signals: // TODO: better signalling for the various possible state changes - especially errors protected: /* variables */ + QString m_internalId; AccountData data; // current task we are executing here diff --git a/launcher/minecraft/auth/flows/AuthContext.cpp b/launcher/minecraft/auth/flows/AuthContext.cpp index 34e2bea8..00957fd4 100644 --- a/launcher/minecraft/auth/flows/AuthContext.cpp +++ b/launcher/minecraft/auth/flows/AuthContext.cpp @@ -18,7 +18,7 @@ #include <Application.h> -using OAuth2 = Katabasis::OAuth2; +using OAuth2 = Katabasis::DeviceFlow; using Activity = Katabasis::Activity; AuthContext::AuthContext(AccountData * data, QObject *parent) : @@ -50,21 +50,17 @@ void AuthContext::initMSA() { return; } - Katabasis::OAuth2::Options opts; + OAuth2::Options opts; opts.scope = "XboxLive.signin offline_access"; opts.clientIdentifier = APPLICATION->msaClientId(); opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"; opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; - opts.listenerPorts = {28562, 28563, 28564, 28565, 28566}; // FIXME: OAuth2 is not aware of our fancy shared pointers m_oauth2 = new OAuth2(opts, m_data->msaToken, this, APPLICATION->network().get()); - m_oauth2->setGrantFlow(Katabasis::OAuth2::GrantFlowDevice); - connect(m_oauth2, &OAuth2::linkingFailed, this, &AuthContext::onOAuthLinkingFailed); - connect(m_oauth2, &OAuth2::linkingSucceeded, this, &AuthContext::onOAuthLinkingSucceeded); - connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &AuthContext::showVerificationUriAndCode); connect(m_oauth2, &OAuth2::activityChanged, this, &AuthContext::onOAuthActivityChanged); + connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &AuthContext::showVerificationUriAndCode); } void AuthContext::initMojang() { @@ -78,7 +74,7 @@ void AuthContext::initMojang() { } void AuthContext::onMojangSucceeded() { - doEntitlements(); + doMinecraftProfile(); } @@ -89,50 +85,56 @@ void AuthContext::onMojangFailed() { changeState(m_yggdrasil->accountState(), tr("Mojang user authentication failed.")); } -/* -bool AuthContext::signOut() { - if(isBusy()) { - return false; - } - - start(); - - beginActivity(Activity::LoggingOut); - m_oauth2->unlink(); - m_account = AccountData(); - finishActivity(); - return true; -} -*/ - -void AuthContext::onOAuthLinkingFailed() { - emit hideVerificationUriAndCode(); - finishActivity(); - changeState(STATE_FAILED_HARD, tr("Microsoft user authentication failed.")); -} - -void AuthContext::onOAuthLinkingSucceeded() { - emit hideVerificationUriAndCode(); - auto *o2t = qobject_cast<OAuth2 *>(sender()); - if (!o2t->linked()) { - finishActivity(); - changeState(STATE_FAILED_HARD, tr("Microsoft user authentication ended with an impossible state (succeeded, but not succeeded at the same time).")); - return; - } - QVariantMap extraTokens = o2t->extraTokens(); -#ifndef NDEBUG - if (!extraTokens.isEmpty()) { - qDebug() << "Extra tokens in response:"; - foreach (QString key, extraTokens.keys()) { - qDebug() << "\t" << key << ":" << extraTokens.value(key); +void AuthContext::onOAuthActivityChanged(Katabasis::Activity activity) { + switch(activity) { + case Katabasis::Activity::Idle: + case Katabasis::Activity::LoggingIn: + case Katabasis::Activity::Refreshing: + case Katabasis::Activity::LoggingOut: { + // We asked it to do something, it's doing it. Nothing to act upon. + return; } - } + case Katabasis::Activity::Succeeded: { + // Succeeded or did not invalidate tokens + emit hideVerificationUriAndCode(); + if (!m_oauth2->linked()) { + finishActivity(); + changeState(STATE_FAILED_HARD, tr("Microsoft user authentication ended with an impossible state (succeeded, but not succeeded at the same time).")); + return; + } + QVariantMap extraTokens = m_oauth2->extraTokens(); +#ifndef NDEBUG + if (!extraTokens.isEmpty()) { + qDebug() << "Extra tokens in response:"; + foreach (QString key, extraTokens.keys()) { + qDebug() << "\t" << key << ":" << extraTokens.value(key); + } + } #endif - doUserAuth(); -} + doUserAuth(); + return; + } + case Katabasis::Activity::FailedSoft: { + emit hideVerificationUriAndCode(); + finishActivity(); + changeState(STATE_FAILED_SOFT, tr("Microsoft user authentication failed with a soft error.")); + return; + } + case Katabasis::Activity::FailedGone: + case Katabasis::Activity::FailedHard: { + emit hideVerificationUriAndCode(); + finishActivity(); + changeState(STATE_FAILED_HARD, tr("Microsoft user authentication failed.")); + return; + } + default: { + emit hideVerificationUriAndCode(); + finishActivity(); + changeState(STATE_FAILED_HARD, tr("Microsoft user authentication completed with an unrecognized result.")); + return; + } -void AuthContext::onOAuthActivityChanged(Katabasis::Activity activity) { - // respond to activity change here + } } void AuthContext::doUserAuth() { @@ -226,7 +228,7 @@ void AuthContext::doSTSAuthMinecraft() { void AuthContext::processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) { if(error == QNetworkReply::AuthenticationRequiredError) { - QJsonParseError jsonError; + QJsonParseError jsonError; QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError); if(jsonError.error) { qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString(); @@ -543,6 +545,10 @@ void AuthContext::onMinecraftProfileDone( #endif if (error == QNetworkReply::ContentNotFoundError) { // NOTE: Succeed even if we do not have a profile. This is a valid account state. + if(m_data->type == AccountType::Mojang) { + m_data->minecraftEntitlement.canPlayMinecraft = false; + m_data->minecraftEntitlement.ownsMinecraft = false; + } m_data->minecraftProfile = MinecraftProfile(); succeed(); return; @@ -560,6 +566,9 @@ void AuthContext::onMinecraftProfileDone( } if(m_data->type == AccountType::Mojang) { + auto validProfile = m_data->minecraftProfile.validity == Katabasis::Validity::Certain; + m_data->minecraftEntitlement.canPlayMinecraft = validProfile; + m_data->minecraftEntitlement.ownsMinecraft = validProfile; doMigrationEligibilityCheck(); } else { diff --git a/launcher/minecraft/auth/flows/AuthContext.h b/launcher/minecraft/auth/flows/AuthContext.h index dcb91613..5e4e9edc 100644 --- a/launcher/minecraft/auth/flows/AuthContext.h +++ b/launcher/minecraft/auth/flows/AuthContext.h @@ -7,7 +7,7 @@ #include <QNetworkReply> #include <QImage> -#include <katabasis/OAuth2.h> +#include <katabasis/DeviceFlow.h> #include "Yggdrasil.h" #include "../AccountData.h" #include "../AccountTask.h" @@ -35,9 +35,6 @@ signals: private slots: // OAuth-specific callbacks - void onOAuthLinkingSucceeded(); - void onOAuthLinkingFailed(); - void onOAuthActivityChanged(Katabasis::Activity activity); // Yggdrasil specific callbacks @@ -87,7 +84,7 @@ protected: void clearTokens(); protected: - Katabasis::OAuth2 *m_oauth2 = nullptr; + Katabasis::DeviceFlow *m_oauth2 = nullptr; Yggdrasil *m_yggdrasil = nullptr; int m_requestsDone = 0; diff --git a/launcher/minecraft/auth/flows/MSAInteractive.cpp b/launcher/minecraft/auth/flows/MSAInteractive.cpp index 6c597cf7..525aaf88 100644 --- a/launcher/minecraft/auth/flows/MSAInteractive.cpp +++ b/launcher/minecraft/auth/flows/MSAInteractive.cpp @@ -17,7 +17,6 @@ void MSAInteractive::executeTask() { m_oauth2->setExtraRequestParams(extraOpts); beginActivity(Katabasis::Activity::LoggingIn); - m_oauth2->unlink(); *m_data = AccountData(); - m_oauth2->link(); + m_oauth2->login(); } diff --git a/launcher/ui/widgets/VersionListView.cpp b/launcher/ui/widgets/VersionListView.cpp index 8424fedd..aba0b1a1 100644 --- a/launcher/ui/widgets/VersionListView.cpp +++ b/launcher/ui/widgets/VersionListView.cpp @@ -19,7 +19,6 @@ #include <QDrag> #include <QPainter> #include "VersionListView.h" -#include "Common.h" VersionListView::VersionListView(QWidget *parent) :QTreeView ( parent ) |