aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/auth/Parsers.cpp
diff options
context:
space:
mode:
authorSefa Eyeoglu <contact@scrumplex.net>2023-08-14 18:16:53 +0200
committerSefa Eyeoglu <contact@scrumplex.net>2023-08-14 18:16:53 +0200
commit91ba4cf75ee30c64779edb5b7644e5a830de5026 (patch)
treeaa8c2433bfc3a54577aceeb706c4c2cd0986c95d /launcher/minecraft/auth/Parsers.cpp
parent779f70057b021e285afd60cc650a14cd5feacffd (diff)
downloadPrismLauncher-91ba4cf75ee30c64779edb5b7644e5a830de5026.tar.gz
PrismLauncher-91ba4cf75ee30c64779edb5b7644e5a830de5026.tar.bz2
PrismLauncher-91ba4cf75ee30c64779edb5b7644e5a830de5026.zip
chore: reformat
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
Diffstat (limited to 'launcher/minecraft/auth/Parsers.cpp')
-rw-r--r--launcher/minecraft/auth/Parsers.cpp192
1 files changed, 103 insertions, 89 deletions
diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp
index 98326272..f6179a93 100644
--- a/launcher/minecraft/auth/Parsers.cpp
+++ b/launcher/minecraft/auth/Parsers.cpp
@@ -2,46 +2,51 @@
#include "Json.h"
#include "Logging.h"
-#include <QJsonDocument>
-#include <QJsonArray>
#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
namespace Parsers {
-bool getDateTime(QJsonValue value, QDateTime & out) {
- if(!value.isString()) {
+bool getDateTime(QJsonValue value, QDateTime& out)
+{
+ if (!value.isString()) {
return false;
}
out = QDateTime::fromString(value.toString(), Qt::ISODate);
return out.isValid();
}
-bool getString(QJsonValue value, QString & out) {
- if(!value.isString()) {
+bool getString(QJsonValue value, QString& out)
+{
+ if (!value.isString()) {
return false;
}
out = value.toString();
return true;
}
-bool getNumber(QJsonValue value, double & out) {
- if(!value.isDouble()) {
+bool getNumber(QJsonValue value, double& out)
+{
+ if (!value.isDouble()) {
return false;
}
out = value.toDouble();
return true;
}
-bool getNumber(QJsonValue value, int64_t & out) {
- if(!value.isDouble()) {
+bool getNumber(QJsonValue value, int64_t& out)
+{
+ if (!value.isDouble()) {
return false;
}
- out = (int64_t) value.toDouble();
+ out = (int64_t)value.toDouble();
return true;
}
-bool getBool(QJsonValue value, bool & out) {
- if(!value.isBool()) {
+bool getBool(QJsonValue value, bool& out)
+{
+ if (!value.isBool()) {
return false;
}
out = value.toBool();
@@ -74,49 +79,50 @@ bool getBool(QJsonValue value, bool & out) {
// 2148916238 = child account not linked to a family
*/
-bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString name) {
- qDebug() << "Parsing" << name <<":";
+bool parseXTokenResponse(QByteArray& data, Katabasis::Token& output, QString name)
+{
+ qDebug() << "Parsing" << name << ":";
qCDebug(authCredentials()) << data;
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
return false;
}
auto obj = doc.object();
- if(!getDateTime(obj.value("IssueInstant"), output.issueInstant)) {
+ if (!getDateTime(obj.value("IssueInstant"), output.issueInstant)) {
qWarning() << "User IssueInstant is not a timestamp";
return false;
}
- if(!getDateTime(obj.value("NotAfter"), output.notAfter)) {
+ if (!getDateTime(obj.value("NotAfter"), output.notAfter)) {
qWarning() << "User NotAfter is not a timestamp";
return false;
}
- if(!getString(obj.value("Token"), output.token)) {
+ if (!getString(obj.value("Token"), output.token)) {
qWarning() << "User Token is not a string";
return false;
}
auto arrayVal = obj.value("DisplayClaims").toObject().value("xui");
- if(!arrayVal.isArray()) {
+ if (!arrayVal.isArray()) {
qWarning() << "Missing xui claims array";
return false;
}
bool foundUHS = false;
- for(auto item: arrayVal.toArray()) {
- if(!item.isObject()) {
+ for (auto item : arrayVal.toArray()) {
+ if (!item.isObject()) {
continue;
}
auto obj_ = item.toObject();
- if(obj_.contains("uhs")) {
+ if (obj_.contains("uhs")) {
foundUHS = true;
} else {
continue;
}
// consume all 'display claims' ... whatever that means
- for(auto iter = obj_.begin(); iter != obj_.end(); iter++) {
+ for (auto iter = obj_.begin(); iter != obj_.end(); iter++) {
QString claim;
- if(!getString(obj_.value(iter.key()), claim)) {
+ if (!getString(obj_.value(iter.key()), claim)) {
qWarning() << "display claim " << iter.key() << " is not a string...";
return false;
}
@@ -125,7 +131,7 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na
break;
}
- if(!foundUHS) {
+ if (!foundUHS) {
qWarning() << "Missing uhs";
return false;
}
@@ -134,46 +140,47 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na
return true;
}
-bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
+bool parseMinecraftProfile(QByteArray& data, MinecraftProfile& output)
+{
qDebug() << "Parsing Minecraft profile...";
qCDebug(authCredentials()) << data;
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
return false;
}
auto obj = doc.object();
- if(!getString(obj.value("id"), output.id)) {
+ if (!getString(obj.value("id"), output.id)) {
qWarning() << "Minecraft profile id is not a string";
return false;
}
- if(!getString(obj.value("name"), output.name)) {
+ if (!getString(obj.value("name"), output.name)) {
qWarning() << "Minecraft profile name is not a string";
return false;
}
auto skinsArray = obj.value("skins").toArray();
- for(auto skin: skinsArray) {
+ for (auto skin : skinsArray) {
auto skinObj = skin.toObject();
Skin skinOut;
- if(!getString(skinObj.value("id"), skinOut.id)) {
+ if (!getString(skinObj.value("id"), skinOut.id)) {
continue;
}
QString state;
- if(!getString(skinObj.value("state"), state)) {
+ if (!getString(skinObj.value("state"), state)) {
continue;
}
- if(state != "ACTIVE") {
+ if (state != "ACTIVE") {
continue;
}
- if(!getString(skinObj.value("url"), skinOut.url)) {
+ if (!getString(skinObj.value("url"), skinOut.url)) {
continue;
}
- if(!getString(skinObj.value("variant"), skinOut.variant)) {
+ if (!getString(skinObj.value("variant"), skinOut.variant)) {
continue;
}
// we deal with only the active skin
@@ -183,23 +190,23 @@ bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
auto capesArray = obj.value("capes").toArray();
QString currentCape;
- for(auto cape: capesArray) {
+ for (auto cape : capesArray) {
auto capeObj = cape.toObject();
Cape capeOut;
- if(!getString(capeObj.value("id"), capeOut.id)) {
+ if (!getString(capeObj.value("id"), capeOut.id)) {
continue;
}
QString state;
- if(!getString(capeObj.value("state"), state)) {
+ if (!getString(capeObj.value("state"), state)) {
continue;
}
- if(state == "ACTIVE") {
+ if (state == "ACTIVE") {
currentCape = capeOut.id;
}
- if(!getString(capeObj.value("url"), capeOut.url)) {
+ if (!getString(capeObj.value("url"), capeOut.url)) {
continue;
}
- if(!getString(capeObj.value("alias"), capeOut.alias)) {
+ if (!getString(capeObj.value("alias"), capeOut.alias)) {
continue;
}
@@ -211,30 +218,33 @@ bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
}
namespace {
- // these skin URLs are for the MHF_Steve and MHF_Alex accounts (made by a Mojang employee)
- // they are needed because the session server doesn't return skin urls for default skins
- static const QString SKIN_URL_STEVE = "http://textures.minecraft.net/texture/1a4af718455d4aab528e7a61f86fa25e6a369d1768dcb13f7df319a713eb810b";
- static const QString SKIN_URL_ALEX = "http://textures.minecraft.net/texture/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032";
-
- bool isDefaultModelSteve(QString uuid) {
- // need to calculate *Java* hashCode of UUID
- // if number is even, skin/model is steve, otherwise it is alex
-
- // just in case dashes are in the id
- uuid.remove('-');
+// these skin URLs are for the MHF_Steve and MHF_Alex accounts (made by a Mojang employee)
+// they are needed because the session server doesn't return skin urls for default skins
+static const QString SKIN_URL_STEVE =
+ "http://textures.minecraft.net/texture/1a4af718455d4aab528e7a61f86fa25e6a369d1768dcb13f7df319a713eb810b";
+static const QString SKIN_URL_ALEX =
+ "http://textures.minecraft.net/texture/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032";
+
+bool isDefaultModelSteve(QString uuid)
+{
+ // need to calculate *Java* hashCode of UUID
+ // if number is even, skin/model is steve, otherwise it is alex
- if (uuid.size() != 32) {
- return true;
- }
+ // just in case dashes are in the id
+ uuid.remove('-');
- // qulonglong is guaranteed to be 64 bits
- // we need to use unsigned numbers to guarantee truncation below
- qulonglong most = uuid.left(16).toULongLong(nullptr, 16);
- qulonglong least = uuid.right(16).toULongLong(nullptr, 16);
- qulonglong xored = most ^ least;
- return ((static_cast<quint32>(xored >> 32)) ^ static_cast<quint32>(xored)) % 2 == 0;
+ if (uuid.size() != 32) {
+ return true;
}
+
+ // qulonglong is guaranteed to be 64 bits
+ // we need to use unsigned numbers to guarantee truncation below
+ qulonglong most = uuid.left(16).toULongLong(nullptr, 16);
+ qulonglong least = uuid.right(16).toULongLong(nullptr, 16);
+ qulonglong xored = most ^ least;
+ return ((static_cast<quint32>(xored >> 32)) ^ static_cast<quint32>(xored)) % 2 == 0;
}
+} // namespace
/**
Uses session server for skin/cape lookup instead of profile,
@@ -270,31 +280,32 @@ decoded base64 "value":
}
*/
-bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
+bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output)
+{
qDebug() << "Parsing Minecraft profile...";
qCDebug(authCredentials()) << data;
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response as JSON: " << jsonError.errorString();
return false;
}
auto obj = Json::requireObject(doc, "mojang minecraft profile");
- if(!getString(obj.value("id"), output.id)) {
+ if (!getString(obj.value("id"), output.id)) {
qWarning() << "Minecraft profile id is not a string";
return false;
}
- if(!getString(obj.value("name"), output.name)) {
+ if (!getString(obj.value("name"), output.name)) {
qWarning() << "Minecraft profile name is not a string";
return false;
}
auto propsArray = obj.value("properties").toArray();
QByteArray texturePayload;
- for( auto p : propsArray) {
+ for (auto p : propsArray) {
auto pObj = p.toObject();
auto name = pObj.value("name");
if (!name.isString() || name.toString() != "textures") {
@@ -321,7 +332,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
}
doc = QJsonDocument::fromJson(texturePayload, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response as JSON: " << jsonError.errorString();
return false;
}
@@ -357,8 +368,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
// might not be present
getString(meta.value("model"), skinOut.variant);
}
- }
- else if (idx.key() == "CAPE") {
+ } else if (idx.key() == "CAPE") {
auto cape = idx->toObject();
if (!getString(cape.value("url"), capeOut.url)) {
qWarning() << "Cape url is not a string";
@@ -374,7 +384,7 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
output.skin = skinOut;
if (capeOut.alias == "cape") {
- output.capes = QMap<QString, Cape>({{capeOut.alias, capeOut}});
+ output.capes = QMap<QString, Cape>({ { capeOut.alias, capeOut } });
output.currentCape = capeOut.alias;
}
@@ -382,13 +392,14 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
return true;
}
-bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) {
+bool parseMinecraftEntitlements(QByteArray& data, MinecraftEntitlement& output)
+{
qDebug() << "Parsing Minecraft entitlements...";
qCDebug(authCredentials()) << data;
QJsonParseError jsonError;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response from user.auth.xboxlive.com as JSON: " << jsonError.errorString();
return false;
}
@@ -398,16 +409,16 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output)
output.ownsMinecraft = false;
auto itemsArray = obj.value("items").toArray();
- for(auto item: itemsArray) {
+ for (auto item : itemsArray) {
auto itemObj = item.toObject();
QString name;
- if(!getString(itemObj.value("name"), name)) {
+ if (!getString(itemObj.value("name"), name)) {
continue;
}
- if(name == "game_minecraft") {
+ if (name == "game_minecraft") {
output.canPlayMinecraft = true;
}
- if(name == "product_minecraft") {
+ if (name == "product_minecraft") {
output.ownsMinecraft = true;
}
}
@@ -415,47 +426,50 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output)
return true;
}
-bool parseRolloutResponse(QByteArray & data, bool& result) {
+bool parseRolloutResponse(QByteArray& data, bool& result)
+{
qDebug() << "Parsing Rollout response...";
qCDebug(authCredentials()) << data;
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();
+ 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)) {
+ if (!getString(obj.value("feature"), feature)) {
qWarning() << "Rollout feature is not a string";
return false;
}
- if(feature != "msamigration") {
+ if (feature != "msamigration") {
qWarning() << "Rollout feature is not what we expected (msamigration), but is instead \"" << feature << "\"";
return false;
}
- if(!getBool(obj.value("rollout"), result)) {
+ if (!getBool(obj.value("rollout"), result)) {
qWarning() << "Rollout feature is not a string";
return false;
}
return true;
}
-bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
+bool parseMojangResponse(QByteArray& data, Katabasis::Token& output)
+{
QJsonParseError jsonError;
qDebug() << "Parsing Mojang response...";
qCDebug(authCredentials()) << data;
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
- if(jsonError.error) {
+ if (jsonError.error) {
qWarning() << "Failed to parse response from api.minecraftservices.com/launcher/login as JSON: " << jsonError.errorString();
return false;
}
auto obj = doc.object();
double expires_in = 0;
- if(!getNumber(obj.value("expires_in"), expires_in)) {
+ if (!getNumber(obj.value("expires_in"), expires_in)) {
qWarning() << "expires_in is not a valid number";
return false;
}
@@ -464,13 +478,13 @@ bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
output.notAfter = currentTime.addSecs(expires_in);
QString username;
- if(!getString(obj.value("username"), username)) {
+ if (!getString(obj.value("username"), username)) {
qWarning() << "username is not valid";
return false;
}
// TODO: it's a JWT... validate it?
- if(!getString(obj.value("access_token"), output.token)) {
+ if (!getString(obj.value("access_token"), output.token)) {
qWarning() << "access_token is not valid";
return false;
}
@@ -479,4 +493,4 @@ bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
return true;
}
-}
+} // namespace Parsers