Add dialog to select profile if multiple availableProfiles
Resolves https://github.com/unmojang/FjordLauncher/issues/29 and obsoletes https://github.com/unmojang/FjordLauncher/pull/34. This implementation follows the authlib-injector specification: https://github.com/yushijinhun/authlib-injector/wiki/%E5%90%AF%E5%8A%A8%E5%99%A8%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E8%B4%A6%E6%88%B7%E7%9A%84%E6%B7%BB%E5%8A%A0 ([Google translate to English](https://github-com.translate.goog/yushijinhun/authlib-injector/wiki/%E5%90%AF%E5%8A%A8%E5%99%A8%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83?_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=en-US))
This commit is contained in:
parent
a1537bf42d
commit
8990841c8b
@ -1,4 +1,5 @@
|
|||||||
#include "YggdrasilStep.h"
|
#include "YggdrasilStep.h"
|
||||||
|
#include <QInputDialog>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include "net/RawHeaderProxy.h"
|
#include "net/RawHeaderProxy.h"
|
||||||
@ -48,10 +49,9 @@ void YggdrasilStep::login(QString password)
|
|||||||
req.insert("username", m_data->userName());
|
req.insert("username", m_data->userName());
|
||||||
req.insert("password", password);
|
req.insert("password", password);
|
||||||
req.insert("requestUser", false);
|
req.insert("requestUser", false);
|
||||||
//
|
|
||||||
// If we already have a client token, give it to the server.
|
// If we already have a client token, give it to the server.
|
||||||
// Otherwise, let the server give us one.
|
// Otherwise, let the server give us one.
|
||||||
|
|
||||||
m_data->generateClientTokenIfMissing();
|
m_data->generateClientTokenIfMissing();
|
||||||
req.insert("clientToken", m_data->clientToken());
|
req.insert("clientToken", m_data->clientToken());
|
||||||
|
|
||||||
@ -79,19 +79,23 @@ void YggdrasilStep::refresh()
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* {
|
* {
|
||||||
* "clientToken": "client identifier"
|
* "clientToken": "client identifier",
|
||||||
* "accessToken": "current access token to be refreshed"
|
* "accessToken": "current access token to be refreshed",
|
||||||
* "selectedProfile": // specifying this causes errors
|
* "selectedProfile": {
|
||||||
* {
|
* "id": "profile ID",
|
||||||
* "id": "profile ID"
|
* "name": "profile name"
|
||||||
* "name": "profile name"
|
* },
|
||||||
* }
|
|
||||||
* "requestUser": true/false // request the user structure
|
* "requestUser": true/false // request the user structure
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
QJsonObject selectedProfile;
|
||||||
|
selectedProfile.insert("id", m_data->profileId());
|
||||||
|
selectedProfile.insert("name", m_data->profileName());
|
||||||
|
|
||||||
QJsonObject req;
|
QJsonObject req;
|
||||||
req.insert("clientToken", m_data->clientToken());
|
req.insert("clientToken", m_data->clientToken());
|
||||||
req.insert("accessToken", m_data->accessToken());
|
req.insert("accessToken", m_data->accessToken());
|
||||||
|
req.insert("selectedProfile", selectedProfile);
|
||||||
req.insert("requestUser", false);
|
req.insert("requestUser", false);
|
||||||
|
|
||||||
QJsonDocument doc(req);
|
QJsonDocument doc(req);
|
||||||
@ -238,17 +242,49 @@ void YggdrasilStep::processResponse(QJsonObject responseData)
|
|||||||
// Get UUID here since we need it for later
|
// Get UUID here since we need it for later
|
||||||
// FIXME: Here is a simple workaround for now,, which uses the first available profile when selectedProfile is not provided
|
// FIXME: Here is a simple workaround for now,, which uses the first available profile when selectedProfile is not provided
|
||||||
auto profile = responseData.value("selectedProfile");
|
auto profile = responseData.value("selectedProfile");
|
||||||
if (!profile.isObject()) {
|
if (profile.isObject()) {
|
||||||
|
m_didSelectProfile = false;
|
||||||
|
} else {
|
||||||
|
if (m_didSelectProfile) {
|
||||||
|
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't save our selected profile."));
|
||||||
|
}
|
||||||
auto profiles = responseData.value("availableProfiles");
|
auto profiles = responseData.value("availableProfiles");
|
||||||
if (!profiles.isArray()) {
|
if (!profiles.isArray()) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send available profiles."));
|
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send available profiles."));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (profiles.toArray().isEmpty()) {
|
const auto& profilesArray = profiles.toArray();
|
||||||
|
if (profilesArray.isEmpty()) {
|
||||||
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Account has no available profile."));
|
emit finished(AccountTaskState::STATE_FAILED_HARD, tr("Account has no available profile."));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else if (profilesArray.size() == 1) {
|
||||||
profile = profiles.toArray().first();
|
profile = profiles.toArray().first();
|
||||||
|
} else {
|
||||||
|
std::map<QString, QJsonValue> profileMap;
|
||||||
|
QStringList profileNames;
|
||||||
|
|
||||||
|
const auto& invalidProfileMessage = tr("Authentication server sent an invalid available profile.");
|
||||||
|
for (const auto& profileValue : profilesArray) {
|
||||||
|
if (!profileValue.isObject()) {
|
||||||
|
emit finished(AccountTaskState::STATE_FAILED_HARD, invalidProfileMessage);
|
||||||
|
}
|
||||||
|
const auto& profileNameValue = profileValue.toObject().value("name");
|
||||||
|
if (!profileNameValue.isString()) {
|
||||||
|
emit finished(AccountTaskState::STATE_FAILED_HARD, invalidProfileMessage);
|
||||||
|
}
|
||||||
|
const auto& profileName = profileNameValue.toString();
|
||||||
|
profileMap.insert({ profileName, profileValue });
|
||||||
|
profileNames.append(profileName);
|
||||||
|
}
|
||||||
|
bool ok;
|
||||||
|
const auto& profileName =
|
||||||
|
QInputDialog::getItem(nullptr, "Select a player", "Select a player:", profileNames, 0, false, &ok);
|
||||||
|
|
||||||
|
if (!ok || profileName.isEmpty()) {
|
||||||
|
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Authentication cancelled."));
|
||||||
|
}
|
||||||
|
profile = profileMap[profileName];
|
||||||
|
m_didSelectProfile = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +303,12 @@ void YggdrasilStep::processResponse(QJsonObject responseData)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_didSelectProfile) {
|
||||||
|
// The authlib-injector specification requires that we refresh immediately after the user has selected a profile:
|
||||||
|
// https://github.com/yushijinhun/authlib-injector/wiki/%E5%90%AF%E5%8A%A8%E5%99%A8%E6%8A%80%E6%9C%AF%E8%A7%84%E8%8C%83#%E8%B4%A6%E6%88%B7%E7%9A%84%E6%B7%BB%E5%8A%A0
|
||||||
|
return refresh();
|
||||||
|
}
|
||||||
|
|
||||||
emit finished(AccountTaskState::STATE_WORKING, "Logged in");
|
emit finished(AccountTaskState::STATE_WORKING, "Logged in");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,4 +33,5 @@ class YggdrasilStep : public AuthStep {
|
|||||||
std::shared_ptr<QByteArray> m_response;
|
std::shared_ptr<QByteArray> m_response;
|
||||||
Net::Upload::Ptr m_request;
|
Net::Upload::Ptr m_request;
|
||||||
NetJob::Ptr m_task;
|
NetJob::Ptr m_task;
|
||||||
|
bool m_didSelectProfile = false;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user