Removed AuthRequest and NetAction

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97
2024-05-13 23:25:08 +03:00
parent f15981d786
commit 3336f8107c
50 changed files with 381 additions and 743 deletions

View File

@@ -1,16 +1,20 @@
#include "EntitlementsStep.h"
#include <QList>
#include <QNetworkRequest>
#include <QUrl>
#include <QUuid>
#include <memory>
#include "Application.h"
#include "Logging.h"
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "net/Download.h"
#include "net/StaticHeaderProxy.h"
#include "tasks/Task.h"
EntitlementsStep::EntitlementsStep(AccountData* data) : AuthStep(data) {}
EntitlementsStep::~EntitlementsStep() noexcept = default;
QString EntitlementsStep::describe()
{
return tr("Determining game ownership.");
@@ -19,35 +23,31 @@ QString EntitlementsStep::describe()
void EntitlementsStep::perform()
{
auto uuid = QUuid::createUuid();
m_entitlementsRequestId = uuid.toString().remove('{').remove('}');
auto url = "https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlementsRequestId;
QNetworkRequest request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Accept", "application/json");
request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &EntitlementsStep::onRequestDone);
requestor->get(request);
m_entitlements_request_id = uuid.toString().remove('{').remove('}');
QUrl url("https://api.minecraftservices.com/entitlements/license?requestId=" + m_entitlements_request_id);
auto headers = QList<Net::HeaderPair>{ { "Content-Type", "application/json" },
{ "Accept", "application/json" },
{ "Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8() } };
m_response.reset(new QByteArray());
m_task = Net::Download::makeByteArray(url, m_response);
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
connect(m_task.get(), &Task::finished, this, &EntitlementsStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
qDebug() << "Getting entitlements...";
}
void EntitlementsStep::rehydrate()
void EntitlementsStep::onRequestDone()
{
// NOOP, for now. We only save bools and there's nothing to check.
}
void EntitlementsStep::onRequestDone([[maybe_unused]] QNetworkReply::NetworkError error,
QByteArray data,
[[maybe_unused]] QList<QNetworkReply::RawHeaderPair> headers)
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
qCDebug(authCredentials()) << data;
qCDebug(authCredentials()) << *m_response;
// TODO: check presence of same entitlementsRequestId?
// TODO: validate JWTs?
Parsers::parseMinecraftEntitlements(data, m_data->minecraftEntitlement);
Parsers::parseMinecraftEntitlements(*m_response, m_data->minecraftEntitlement);
emit finished(AccountTaskState::STATE_WORKING, tr("Got entitlements"));
}

View File

@@ -1,24 +1,26 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Download.h"
class EntitlementsStep : public AuthStep {
Q_OBJECT
public:
explicit EntitlementsStep(AccountData* data);
virtual ~EntitlementsStep() noexcept;
virtual ~EntitlementsStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
QString m_entitlementsRequestId;
QString m_entitlements_request_id;
std::shared_ptr<QByteArray> m_response;
Net::Download::Ptr m_task;
};

View File

@@ -3,13 +3,10 @@
#include <QNetworkRequest>
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "Application.h"
GetSkinStep::GetSkinStep(AccountData* data) : AuthStep(data) {}
GetSkinStep::~GetSkinStep() noexcept = default;
QString GetSkinStep::describe()
{
return tr("Getting skin.");
@@ -17,25 +14,20 @@ QString GetSkinStep::describe()
void GetSkinStep::perform()
{
auto url = QUrl(m_data->minecraftProfile.skin.url);
QNetworkRequest request = QNetworkRequest(url);
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &GetSkinStep::onRequestDone);
requestor->get(request);
QUrl url(m_data->minecraftProfile.skin.url);
m_response.reset(new QByteArray());
m_task = Net::Download::makeByteArray(url, m_response);
connect(m_task.get(), &Task::finished, this, &GetSkinStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
}
void GetSkinStep::rehydrate()
void GetSkinStep::onRequestDone()
{
// NOOP, for now.
}
void GetSkinStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
if (error == QNetworkReply::NoError) {
m_data->minecraftProfile.skin.data = data;
}
if (m_task->error() == QNetworkReply::NoError)
m_data->minecraftProfile.skin.data = *m_response;
emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Got skin"));
}

View File

@@ -1,21 +1,25 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Download.h"
class GetSkinStep : public AuthStep {
Q_OBJECT
public:
explicit GetSkinStep(AccountData* data);
virtual ~GetSkinStep() noexcept;
virtual ~GetSkinStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
std::shared_ptr<QByteArray> m_response;
Net::Download::Ptr m_task;
};

View File

@@ -1,17 +1,18 @@
#include "LauncherLoginStep.h"
#include <QNetworkRequest>
#include <QUrl>
#include "Application.h"
#include "Logging.h"
#include "minecraft/auth/AccountTask.h"
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "net/NetUtils.h"
#include "net/StaticHeaderProxy.h"
#include "net/Upload.h"
LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {}
LauncherLoginStep::~LauncherLoginStep() noexcept = default;
QString LauncherLoginStep::describe()
{
return tr("Accessing Mojang services.");
@@ -19,7 +20,7 @@ QString LauncherLoginStep::describe()
void LauncherLoginStep::perform()
{
auto requestURL = "https://api.minecraftservices.com/launcher/login";
QUrl url("https://api.minecraftservices.com/launcher/login");
auto uhs = m_data->mojangservicesToken.extra["uhs"].toString();
auto xToken = m_data->mojangservicesToken.token;
@@ -31,40 +32,37 @@ void LauncherLoginStep::perform()
)XXX";
auto requestBody = mc_auth_template.arg(uhs, xToken);
QNetworkRequest request = QNetworkRequest(QUrl(requestURL));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Accept", "application/json");
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &LauncherLoginStep::onRequestDone);
requestor->post(request, requestBody.toUtf8());
auto headers = QList<Net::HeaderPair>{
{ "Content-Type", "application/json" },
{ "Accept", "application/json" },
};
m_response.reset(new QByteArray());
m_task = Net::Upload::makeByteArray(url, m_response, requestBody.toUtf8());
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
connect(m_task.get(), &Task::finished, this, &LauncherLoginStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
qDebug() << "Getting Minecraft access token...";
}
void LauncherLoginStep::rehydrate()
void LauncherLoginStep::onRequestDone()
{
// TODO: check the token validity
}
void LauncherLoginStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
qCDebug(authCredentials()) << data;
if (error != QNetworkReply::NoError) {
qWarning() << "Reply error:" << error;
qCDebug(authCredentials()) << data;
if (Net::isApplicationError(error)) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_));
qCDebug(authCredentials()) << *m_response;
if (m_task->error() != QNetworkReply::NoError) {
qWarning() << "Reply error:" << m_task->error();
if (Net::isApplicationError(m_task->error())) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to get Minecraft access token: %1").arg(m_task->errorString()));
} else {
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(requestor->errorString_));
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to get Minecraft access token: %1").arg(m_task->errorString()));
}
return;
}
if (!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) {
if (!Parsers::parseMojangResponse(*m_response, m_data->yggdrasilToken)) {
qWarning() << "Could not parse login_with_xbox response...";
qCDebug(authCredentials()) << data;
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to parse the Minecraft access token response."));
return;
}

View File

@@ -1,21 +1,25 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Upload.h"
class LauncherLoginStep : public AuthStep {
Q_OBJECT
public:
explicit LauncherLoginStep(AccountData* data);
virtual ~LauncherLoginStep() noexcept;
virtual ~LauncherLoginStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
std::shared_ptr<QByteArray> m_response;
Net::Upload::Ptr m_task;
};

View File

@@ -37,10 +37,6 @@
#include <QNetworkRequest>
#include "BuildConfig.h"
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "Application.h"
#include "Logging.h"
@@ -63,27 +59,11 @@ MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(ac
connect(m_oauth2, &OAuth2::showVerificationUriAndCode, this, &MSAStep::showVerificationUriAndCode);
}
MSAStep::~MSAStep() noexcept = default;
QString MSAStep::describe()
{
return tr("Logging in with Microsoft account.");
}
void MSAStep::rehydrate()
{
switch (m_action) {
case Refresh: {
// TODO: check the tokens and see if they are old (older than a day)
return;
}
case Login: {
// NOOP
return;
}
}
}
void MSAStep::perform()
{
switch (m_action) {

View File

@@ -48,10 +48,9 @@ class MSAStep : public AuthStep {
public:
explicit MSAStep(AccountData* data, Action action);
virtual ~MSAStep() noexcept;
virtual ~MSAStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;

View File

@@ -2,15 +2,13 @@
#include <QNetworkRequest>
#include "Logging.h"
#include "minecraft/auth/AuthRequest.h"
#include "Application.h"
#include "minecraft/auth/Parsers.h"
#include "net/NetUtils.h"
#include "net/StaticHeaderProxy.h"
MinecraftProfileStep::MinecraftProfileStep(AccountData* data) : AuthStep(data) {}
MinecraftProfileStep::~MinecraftProfileStep() noexcept = default;
QString MinecraftProfileStep::describe()
{
return tr("Fetching the Minecraft profile.");
@@ -18,52 +16,47 @@ QString MinecraftProfileStep::describe()
void MinecraftProfileStep::perform()
{
auto url = QUrl("https://api.minecraftservices.com/minecraft/profile");
QNetworkRequest request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8());
QUrl url("https://api.minecraftservices.com/minecraft/profile");
auto headers = QList<Net::HeaderPair>{ { "Content-Type", "application/json" },
{ "Accept", "application/json" },
{ "Authorization", QString("Bearer %1").arg(m_data->yggdrasilToken.token).toUtf8() } };
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &MinecraftProfileStep::onRequestDone);
requestor->get(request);
m_response.reset(new QByteArray());
m_task = Net::Download::makeByteArray(url, m_response);
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
connect(m_task.get(), &Task::finished, this, &MinecraftProfileStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
}
void MinecraftProfileStep::rehydrate()
void MinecraftProfileStep::onRequestDone()
{
// NOOP, for now. We only save bools and there's nothing to check.
}
void MinecraftProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
qCDebug(authCredentials()) << data;
if (error == QNetworkReply::ContentNotFoundError) {
if (m_task->error() == QNetworkReply::ContentNotFoundError) {
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
m_data->minecraftProfile = MinecraftProfile();
emit finished(AccountTaskState::STATE_SUCCEEDED, tr("Account has no Minecraft profile."));
return;
}
if (error != QNetworkReply::NoError) {
if (m_task->error() != QNetworkReply::NoError) {
qWarning() << "Error getting profile:";
qWarning() << " HTTP Status: " << requestor->httpStatus_;
qWarning() << " Internal error no.: " << error;
qWarning() << " Error string: " << requestor->errorString_;
qWarning() << " HTTP Status: " << m_task->replyStatusCode();
qWarning() << " Internal error no.: " << m_task->error();
qWarning() << " Error string: " << m_task->errorString();
qWarning() << " Response:";
qWarning() << QString::fromUtf8(data);
qWarning() << QString::fromUtf8(*m_response);
if (Net::isApplicationError(error)) {
if (Net::isApplicationError(m_task->error())) {
emit finished(AccountTaskState::STATE_FAILED_SOFT,
tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_));
tr("Minecraft Java profile acquisition failed: %1").arg(m_task->errorString()));
} else {
emit finished(AccountTaskState::STATE_OFFLINE,
tr("Minecraft Java profile acquisition failed: %1").arg(requestor->errorString_));
emit finished(AccountTaskState::STATE_OFFLINE, tr("Minecraft Java profile acquisition failed: %1").arg(m_task->errorString()));
}
return;
}
if (!Parsers::parseMinecraftProfile(data, m_data->minecraftProfile)) {
if (!Parsers::parseMinecraftProfile(*m_response, m_data->minecraftProfile)) {
m_data->minecraftProfile = MinecraftProfile();
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Minecraft Java profile response could not be parsed"));
return;

View File

@@ -1,21 +1,25 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Download.h"
class MinecraftProfileStep : public AuthStep {
Q_OBJECT
public:
explicit MinecraftProfileStep(AccountData* data);
virtual ~MinecraftProfileStep() noexcept;
virtual ~MinecraftProfileStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
std::shared_ptr<QByteArray> m_response;
Net::Download::Ptr m_task;
};

View File

@@ -1,20 +1,12 @@
#include "OfflineStep.h"
#include "Application.h"
OfflineStep::OfflineStep(AccountData* data) : AuthStep(data) {}
OfflineStep::~OfflineStep() noexcept = default;
QString OfflineStep::describe()
{
return tr("Creating offline account.");
}
void OfflineStep::rehydrate()
{
// NOOP
}
void OfflineStep::perform()
{
emit finished(AccountTaskState::STATE_WORKING, tr("Created offline account."));

View File

@@ -1,19 +1,15 @@
#pragma once
#include <QObject>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include <katabasis/DeviceFlow.h>
class OfflineStep : public AuthStep {
Q_OBJECT
public:
explicit OfflineStep(AccountData* data);
virtual ~OfflineStep() noexcept;
virtual ~OfflineStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
};

View File

@@ -4,27 +4,22 @@
#include <QJsonParseError>
#include <QNetworkRequest>
#include "Application.h"
#include "Logging.h"
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "net/NetUtils.h"
#include "net/StaticHeaderProxy.h"
#include "net/Upload.h"
XboxAuthorizationStep::XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind)
: AuthStep(data), m_token(token), m_relyingParty(relyingParty), m_authorizationKind(authorizationKind)
{}
XboxAuthorizationStep::~XboxAuthorizationStep() noexcept = default;
QString XboxAuthorizationStep::describe()
{
return tr("Getting authorization to access %1 services.").arg(m_authorizationKind);
}
void XboxAuthorizationStep::rehydrate()
{
// FIXME: check if the tokens are good?
}
void XboxAuthorizationStep::perform()
{
QString xbox_auth_template = R"XXX(
@@ -41,40 +36,44 @@ void XboxAuthorizationStep::perform()
)XXX";
auto xbox_auth_data = xbox_auth_template.arg(m_data->userToken.token, m_relyingParty);
// http://xboxlive.com
QNetworkRequest request = QNetworkRequest(QUrl("https://xsts.auth.xboxlive.com/xsts/authorize"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Accept", "application/json");
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &XboxAuthorizationStep::onRequestDone);
requestor->post(request, xbox_auth_data.toUtf8());
QUrl url("https://xsts.auth.xboxlive.com/xsts/authorize");
auto headers = QList<Net::HeaderPair>{
{ "Content-Type", "application/json" },
{ "Accept", "application/json" },
};
m_response.reset(new QByteArray());
m_task = Net::Upload::makeByteArray(url, m_response, xbox_auth_data.toUtf8());
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
connect(m_task.get(), &Task::finished, this, &XboxAuthorizationStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
qDebug() << "Getting authorization token for " << m_relyingParty;
}
void XboxAuthorizationStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
void XboxAuthorizationStep::onRequestDone()
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
qCDebug(authCredentials()) << data;
if (error != QNetworkReply::NoError) {
qWarning() << "Reply error:" << error;
if (Net::isApplicationError(error)) {
if (!processSTSError(error, data, headers)) {
qCDebug(authCredentials()) << *m_response;
if (m_task->error() != QNetworkReply::NoError) {
qWarning() << "Reply error:" << m_task->error();
if (Net::isApplicationError(m_task->error())) {
if (!processSTSError()) {
emit finished(AccountTaskState::STATE_FAILED_SOFT,
tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, error));
tr("Failed to get authorization for %1 services. Error %2.").arg(m_authorizationKind, m_task->error()));
} else {
emit finished(AccountTaskState::STATE_FAILED_SOFT,
tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, requestor->errorString_));
tr("Unknown STS error for %1 services: %2").arg(m_authorizationKind, m_task->errorString()));
}
} else {
emit finished(AccountTaskState::STATE_OFFLINE,
tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, requestor->errorString_));
tr("Failed to get authorization for %1 services: %2").arg(m_authorizationKind, m_task->errorString()));
}
return;
}
Katabasis::Token temp;
if (!Parsers::parseXTokenResponse(data, temp, m_authorizationKind)) {
if (!Parsers::parseXTokenResponse(*m_response, temp, m_authorizationKind)) {
emit finished(AccountTaskState::STATE_FAILED_SOFT,
tr("Could not parse authorization response for access to %1 services.").arg(m_authorizationKind));
return;
@@ -91,11 +90,11 @@ void XboxAuthorizationStep::onRequestDone(QNetworkReply::NetworkError error, QBy
emit finished(AccountTaskState::STATE_WORKING, tr("Got authorization to access %1").arg(m_relyingParty));
}
bool XboxAuthorizationStep::processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
bool XboxAuthorizationStep::processSTSError()
{
if (error == QNetworkReply::AuthenticationRequiredError) {
if (m_task->error() == QNetworkReply::AuthenticationRequiredError) {
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
QJsonDocument doc = QJsonDocument::fromJson(*m_response, &jsonError);
if (jsonError.error) {
qWarning() << "Cannot parse error XSTS response as JSON: " << jsonError.errorString();
emit finished(AccountTaskState::STATE_FAILED_SOFT,

View File

@@ -1,29 +1,32 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Upload.h"
class XboxAuthorizationStep : public AuthStep {
Q_OBJECT
public:
explicit XboxAuthorizationStep(AccountData* data, Katabasis::Token* token, QString relyingParty, QString authorizationKind);
virtual ~XboxAuthorizationStep() noexcept;
virtual ~XboxAuthorizationStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private:
bool processSTSError(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers);
bool processSTSError();
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
Katabasis::Token* m_token;
QString m_relyingParty;
QString m_authorizationKind;
std::shared_ptr<QByteArray> m_response;
Net::Upload::Ptr m_task;
};

View File

@@ -3,28 +3,21 @@
#include <QNetworkRequest>
#include <QUrlQuery>
#include "Application.h"
#include "Logging.h"
#include "minecraft/auth/AuthRequest.h"
#include "minecraft/auth/Parsers.h"
#include "net/NetUtils.h"
#include "net/StaticHeaderProxy.h"
XboxProfileStep::XboxProfileStep(AccountData* data) : AuthStep(data) {}
XboxProfileStep::~XboxProfileStep() noexcept = default;
QString XboxProfileStep::describe()
{
return tr("Fetching Xbox profile.");
}
void XboxProfileStep::rehydrate()
{
// NOOP, for now. We only save bools and there's nothing to check.
}
void XboxProfileStep::perform()
{
auto url = QUrl("https://profile.xboxlive.com/users/me/profile/settings");
QUrl url("https://profile.xboxlive.com/users/me/profile/settings");
QUrlQuery q;
q.addQueryItem("settings",
"GameDisplayName,AppDisplayName,AppDisplayPicRaw,GameDisplayPicRaw,"
@@ -33,36 +26,38 @@ void XboxProfileStep::perform()
"PreferredColor,Location,Bio,Watermarks,"
"RealName,RealNameOverride,IsQuarantined");
url.setQuery(q);
auto headers = QList<Net::HeaderPair>{
{ "Content-Type", "application/json" },
{ "Accept", "application/json" },
{ "x-xbl-contract-version", "3" },
{ "Authorization", QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8() }
};
QNetworkRequest request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Accept", "application/json");
request.setRawHeader("x-xbl-contract-version", "3");
request.setRawHeader("Authorization",
QString("XBL3.0 x=%1;%2").arg(m_data->userToken.extra["uhs"].toString(), m_data->xboxApiToken.token).toUtf8());
AuthRequest* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &XboxProfileStep::onRequestDone);
requestor->get(request);
m_response.reset(new QByteArray());
m_task = Net::Download::makeByteArray(url, m_response);
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
connect(m_task.get(), &Task::finished, this, &XboxProfileStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
qDebug() << "Getting Xbox profile...";
}
void XboxProfileStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
void XboxProfileStep::onRequestDone()
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
if (error != QNetworkReply::NoError) {
qWarning() << "Reply error:" << error;
qCDebug(authCredentials()) << data;
if (Net::isApplicationError(error)) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_));
if (m_task->error() != QNetworkReply::NoError) {
qWarning() << "Reply error:" << m_task->error();
qCDebug(authCredentials()) << *m_response;
if (Net::isApplicationError(m_task->error())) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("Failed to retrieve the Xbox profile: %1").arg(m_task->errorString()));
} else {
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to retrieve the Xbox profile: %1").arg(requestor->errorString_));
emit finished(AccountTaskState::STATE_OFFLINE, tr("Failed to retrieve the Xbox profile: %1").arg(m_task->errorString()));
}
return;
}
qCDebug(authCredentials()) << "XBox profile: " << data;
qCDebug(authCredentials()) << "XBox profile: " << *m_response;
emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox profile"));
}

View File

@@ -1,21 +1,25 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Download.h"
class XboxProfileStep : public AuthStep {
Q_OBJECT
public:
explicit XboxProfileStep(AccountData* data);
virtual ~XboxProfileStep() noexcept;
virtual ~XboxProfileStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
std::shared_ptr<QByteArray> m_response;
Net::Download::Ptr m_task;
};

View File

@@ -2,24 +2,18 @@
#include <QNetworkRequest>
#include "minecraft/auth/AuthRequest.h"
#include "Application.h"
#include "minecraft/auth/Parsers.h"
#include "net/NetUtils.h"
#include "net/StaticHeaderProxy.h"
XboxUserStep::XboxUserStep(AccountData* data) : AuthStep(data) {}
XboxUserStep::~XboxUserStep() noexcept = default;
QString XboxUserStep::describe()
{
return tr("Logging in as an Xbox user.");
}
void XboxUserStep::rehydrate()
{
// NOOP, for now. We only save bools and there's nothing to check.
}
void XboxUserStep::perform()
{
QString xbox_auth_template = R"XXX(
@@ -35,36 +29,39 @@ void XboxUserStep::perform()
)XXX";
auto xbox_auth_data = xbox_auth_template.arg(m_data->msaToken.token);
QNetworkRequest request = QNetworkRequest(QUrl("https://user.auth.xboxlive.com/user/authenticate"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
request.setRawHeader("Accept", "application/json");
// set contract-version header (prevent err 400 bad-request?)
// https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/live/rest/additional/httpstandardheaders
request.setRawHeader("x-xbl-contract-version", "1");
QUrl url("https://user.auth.xboxlive.com/user/authenticate");
auto headers = QList<Net::HeaderPair>{
{ "Content-Type", "application/json" },
{ "Accept", "application/json" },
// set contract-version header (prevent err 400 bad-request?)
// https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/reference/live/rest/additional/httpstandardheaders
{ "x-xbl-contract-version", "1" }
};
m_response.reset(new QByteArray());
m_task = Net::Upload::makeByteArray(url, m_response, xbox_auth_data.toUtf8());
m_task->addHeaderProxy(new Net::StaticHeaderProxy(headers));
auto* requestor = new AuthRequest(this);
connect(requestor, &AuthRequest::finished, this, &XboxUserStep::onRequestDone);
requestor->post(request, xbox_auth_data.toUtf8());
connect(m_task.get(), &Task::finished, this, &XboxUserStep::onRequestDone);
m_task->setNetwork(APPLICATION->network());
m_task->start();
qDebug() << "First layer of XBox auth ... commencing.";
}
void XboxUserStep::onRequestDone(QNetworkReply::NetworkError error, QByteArray data, QList<QNetworkReply::RawHeaderPair> headers)
void XboxUserStep::onRequestDone()
{
auto requestor = qobject_cast<AuthRequest*>(QObject::sender());
requestor->deleteLater();
if (error != QNetworkReply::NoError) {
qWarning() << "Reply error:" << error;
if (Net::isApplicationError(error)) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed: %1").arg(requestor->errorString_));
if (m_task->error() != QNetworkReply::NoError) {
qWarning() << "Reply error:" << m_task->error();
if (Net::isApplicationError(m_task->error())) {
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication failed: %1").arg(m_task->errorString()));
} else {
emit finished(AccountTaskState::STATE_OFFLINE, tr("XBox user authentication failed: %1").arg(requestor->errorString_));
emit finished(AccountTaskState::STATE_OFFLINE, tr("XBox user authentication failed: %1").arg(m_task->errorString()));
}
return;
}
Katabasis::Token temp;
if (!Parsers::parseXTokenResponse(data, temp, "UToken")) {
if (!Parsers::parseXTokenResponse(*m_response, temp, "UToken")) {
qWarning() << "Could not parse user authentication response...";
emit finished(AccountTaskState::STATE_FAILED_SOFT, tr("XBox user authentication response could not be understood."));
return;

View File

@@ -1,21 +1,25 @@
#pragma once
#include <QObject>
#include <memory>
#include "QObjectPtr.h"
#include "minecraft/auth/AuthStep.h"
#include "net/Upload.h"
class XboxUserStep : public AuthStep {
Q_OBJECT
public:
explicit XboxUserStep(AccountData* data);
virtual ~XboxUserStep() noexcept;
virtual ~XboxUserStep() noexcept = default;
void perform() override;
void rehydrate() override;
QString describe() override;
private slots:
void onRequestDone(QNetworkReply::NetworkError, QByteArray, QList<QNetworkReply::RawHeaderPair>);
void onRequestDone();
private:
std::shared_ptr<QByteArray> m_response;
Net::Upload::Ptr m_task;
};