aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-08-29 22:55:33 +0200
committerPetr Mrázek <peterix@gmail.com>2021-08-29 22:55:33 +0200
commit317101430148e3bbc52995aa92d668b8473026d9 (patch)
tree0dda85a8fd0b60c7eeba3950842bd1dd876155e2 /launcher
parent7239502675fb68b1a2050c68f483e5d5371114e1 (diff)
downloadPrismLauncher-317101430148e3bbc52995aa92d668b8473026d9.tar.gz
PrismLauncher-317101430148e3bbc52995aa92d668b8473026d9.tar.bz2
PrismLauncher-317101430148e3bbc52995aa92d668b8473026d9.zip
GH-3392 checking for migration status and refresh button in accounts list
Diffstat (limited to 'launcher')
-rw-r--r--launcher/minecraft/auth/AccountList.cpp16
-rw-r--r--launcher/minecraft/auth/AccountList.h1
-rw-r--r--launcher/minecraft/auth/MinecraftAccount.h8
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.cpp68
-rw-r--r--launcher/minecraft/auth/flows/AuthContext.h4
-rw-r--r--launcher/pages/global/AccountListPage.cpp17
-rw-r--r--launcher/pages/global/AccountListPage.h1
-rw-r--r--launcher/pages/global/AccountListPage.ui9
8 files changed, 124 insertions, 0 deletions
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index 59028b60..76af0ac0 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -205,6 +205,18 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
return account->profileName();
}
+ case MigrationColumn: {
+ if(account->isMSA()) {
+ return tr("N/A", "Can Migrate?");
+ }
+ if (account->canMigrate()) {
+ return tr("Yes", "Can Migrate?");
+ }
+ else {
+ return tr("No", "Can Migrate?");
+ }
+ }
+
default:
return QVariant();
}
@@ -238,6 +250,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
return tr("Account");
case TypeColumn:
return tr("Type");
+ case MigrationColumn:
+ return tr("Can Migrate?");
case ProfileNameColumn:
return tr("Profile");
default:
@@ -251,6 +265,8 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
return tr("User name of the account.");
case TypeColumn:
return tr("Type of the account - Mojang or MSA.");
+ case MigrationColumn:
+ return tr("Can this account migrate to Microsoft account?");
case ProfileNameColumn:
return tr("Name of the Minecraft profile associated with the account.");
default:
diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h
index ac3684ee..ed08bb1d 100644
--- a/launcher/minecraft/auth/AccountList.h
+++ b/launcher/minecraft/auth/AccountList.h
@@ -40,6 +40,7 @@ public:
// TODO: Add icon column.
NameColumn = 0,
ProfileNameColumn,
+ MigrationColumn,
TypeColumn,
NUM_COLUMNS
diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h
index 72bb6bd4..5b0c1ec7 100644
--- a/launcher/minecraft/auth/MinecraftAccount.h
+++ b/launcher/minecraft/auth/MinecraftAccount.h
@@ -117,6 +117,14 @@ public: /* queries */
return data.profileName();
}
+ bool canMigrate() const {
+ return data.canMigrateToMSA;
+ }
+
+ bool isMSA() const {
+ return data.type == AccountType::MSA;
+ }
+
QString typeString() const {
switch(data.type) {
case AccountType::Mojang: {
diff --git a/launcher/minecraft/auth/flows/AuthContext.cpp b/launcher/minecraft/auth/flows/AuthContext.cpp
index 9ae99453..5d7d858d 100644
--- a/launcher/minecraft/auth/flows/AuthContext.cpp
+++ b/launcher/minecraft/auth/flows/AuthContext.cpp
@@ -192,6 +192,15 @@ bool getNumber(QJsonValue value, double & out) {
return true;
}
+
+bool getBool(QJsonValue value, bool & out) {
+ if(!value.isBool()) {
+ return false;
+ }
+ out = value.toBool();
+ return true;
+}
+
/*
{
"IssueInstant":"2020-12-07T19:52:08.4463796Z",
@@ -693,6 +702,63 @@ void AuthContext::onMinecraftProfileDone(int, QNetworkReply::NetworkError error,
changeState(STATE_FAILED_HARD, tr("Minecraft Java profile response could not be parsed"));
return;
}
+
+ if(m_data->type == AccountType::Mojang) {
+ doMigrationEligibilityCheck();
+ }
+ else {
+ doGetSkin();
+ }
+}
+
+void AuthContext::doMigrationEligibilityCheck() {
+ setStage(AuthStage::MigrationEligibility);
+ changeState(STATE_WORKING, tr("Starting check for migration eligibility"));
+
+ auto url = QUrl("https://api.minecraftservices.com/rollout/v1/msamigration");
+ QNetworkRequest request = QNetworkRequest(url);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
+
+ Requestor *requestor = new Requestor(mgr, m_oauth2, this);
+ connect(requestor, &Requestor::finished, this, &AuthContext::onMigrationEligibilityCheckDone);
+ requestor->get(request);
+}
+
+bool parseRolloutResponse(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/msamigration 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 != "msamigration") {
+ qWarning() << "Rollout feature is not what we expected (msamigration), but is instead \"" << feature << "\"";
+ return false;
+ }
+ if(!getBool(obj.value("rollout"), result)) {
+ qWarning() << "Rollout feature is not a string";
+ return false;
+ }
+ return true;
+}
+
+void AuthContext::onMigrationEligibilityCheckDone(int, QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers) {
+ if (error == QNetworkReply::NoError) {
+ parseRolloutResponse(data, m_data->canMigrateToMSA);
+ }
doGetSkin();
}
@@ -742,6 +808,8 @@ QString AuthContext::getStateMessage() const {
return tr("Logging in with XBox and Mojang services");
case AuthStage::MinecraftProfile:
return tr("Getting Minecraft profile");
+ case AuthStage::MigrationEligibility:
+ return tr("Checking for migration eligibility");
case AuthStage::Skin:
return tr("Getting Minecraft skin");
case AuthStage::Complete:
diff --git a/launcher/minecraft/auth/flows/AuthContext.h b/launcher/minecraft/auth/flows/AuthContext.h
index 1d9f8f72..7bf69623 100644
--- a/launcher/minecraft/auth/flows/AuthContext.h
+++ b/launcher/minecraft/auth/flows/AuthContext.h
@@ -63,6 +63,9 @@ protected:
void doMinecraftProfile();
Q_SLOT void onMinecraftProfileDone(int, QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+ void doMigrationEligibilityCheck();
+ Q_SLOT void onMigrationEligibilityCheckDone(int, QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
+
void doGetSkin();
Q_SLOT void onSkinDone(int, QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
@@ -86,6 +89,7 @@ protected:
UserAuth,
XboxAuth,
MinecraftProfile,
+ MigrationEligibility,
Skin,
Complete
} m_stage = AuthStage::Initial;
diff --git a/launcher/pages/global/AccountListPage.cpp b/launcher/pages/global/AccountListPage.cpp
index 45b778de..6bb07b22 100644
--- a/launcher/pages/global/AccountListPage.cpp
+++ b/launcher/pages/global/AccountListPage.cpp
@@ -153,6 +153,22 @@ void AccountListPage::on_actionRemove_triggered()
}
}
+void AccountListPage::on_actionRefresh_triggered() {
+ QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
+ if (selection.size() > 0) {
+ QModelIndex selected = selection.first();
+ MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
+ AuthSessionPtr session = std::make_shared<AuthSession>();
+ auto task = account->refresh(session);
+ if (task) {
+ ProgressDialog progDialog(this);
+ progDialog.execWithTask(task.get());
+ // TODO: respond to results of the task
+ }
+ }
+}
+
+
void AccountListPage::on_actionSetDefault_triggered()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
@@ -178,6 +194,7 @@ void AccountListPage::updateButtonStates()
ui->actionSetDefault->setEnabled(selection.size() > 0);
ui->actionUploadSkin->setEnabled(selection.size() > 0);
ui->actionDeleteSkin->setEnabled(selection.size() > 0);
+ ui->actionRefresh->setEnabled(selection.size() > 0);
if(m_accounts->activeAccount().get() == nullptr) {
ui->actionNoDefault->setEnabled(false);
diff --git a/launcher/pages/global/AccountListPage.h b/launcher/pages/global/AccountListPage.h
index 24bb96da..4474802e 100644
--- a/launcher/pages/global/AccountListPage.h
+++ b/launcher/pages/global/AccountListPage.h
@@ -63,6 +63,7 @@ public slots:
void on_actionAddMojang_triggered();
void on_actionAddMicrosoft_triggered();
void on_actionRemove_triggered();
+ void on_actionRefresh_triggered();
void on_actionSetDefault_triggered();
void on_actionNoDefault_triggered();
void on_actionUploadSkin_triggered();
diff --git a/launcher/pages/global/AccountListPage.ui b/launcher/pages/global/AccountListPage.ui
index 887c3d48..8af23a2f 100644
--- a/launcher/pages/global/AccountListPage.ui
+++ b/launcher/pages/global/AccountListPage.ui
@@ -54,6 +54,7 @@
</attribute>
<addaction name="actionAddMicrosoft"/>
<addaction name="actionAddMojang"/>
+ <addaction name="actionRefresh"/>
<addaction name="actionRemove"/>
<addaction name="actionSetDefault"/>
<addaction name="actionNoDefault"/>
@@ -102,6 +103,14 @@
<string>Add Microsoft</string>
</property>
</action>
+ <action name="actionRefresh">
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ <property name="toolTip">
+ <string>Refresh the account tokens</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>