From 984c36e571aae45cdd55da2fb689538198aadd3c Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Mon, 23 Sep 2013 00:23:50 +0200 Subject: Implement basic yggdrasil auth. No fancy login token saving involved. --- logic/net/LoginTask.h | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 logic/net/LoginTask.h (limited to 'logic/net/LoginTask.h') diff --git a/logic/net/LoginTask.h b/logic/net/LoginTask.h new file mode 100644 index 00000000..ba87142d --- /dev/null +++ b/logic/net/LoginTask.h @@ -0,0 +1,62 @@ +/* Copyright 2013 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "logic/tasks/Task.h" +#include + +struct UserInfo +{ + QString username; + QString password; +}; + +struct LoginResponse +{ + QString username; + QString session_id; + QString player_name; + QString player_id; +}; + +class QNetworkReply; + +class LoginTask : public Task +{ + Q_OBJECT +public: + explicit LoginTask(const UserInfo &uInfo, QObject *parent = 0); + LoginResponse getResult() + { + return result; + } + +protected slots: + void legacyLogin(); + void processLegacyReply(QNetworkReply *reply); + void parseLegacyReply(QByteArray data); + + void yggdrasilLogin(); + void processYggdrasilReply(QNetworkReply *reply); + void parseYggdrasilReply(QByteArray data); + +protected: + void executeTask(); + + LoginResponse result; + QNetworkReply *netReply; + UserInfo uInfo; +}; -- cgit From f8b4c2c0b25f89017db2702b60d47df7376b32e6 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Fri, 11 Oct 2013 16:13:01 +0200 Subject: Fix auth for 13w41a --- logic/OneSixInstance.cpp | 1 + logic/net/LoginTask.cpp | 2 +- logic/net/LoginTask.h | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'logic/net/LoginTask.h') diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index 853bcc48..d80f6b37 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -60,6 +60,7 @@ QStringList OneSixInstance::processMinecraftArgs(LoginResponse response) // yggdrasil! token_mapping["auth_username"] = response.username; token_mapping["auth_session"] = response.session_id; + token_mapping["auth_access_token"] = response.access_token; token_mapping["auth_player_name"] = response.player_name; token_mapping["auth_uuid"] = response.player_id; diff --git a/logic/net/LoginTask.cpp b/logic/net/LoginTask.cpp index 5de8efa9..90aac74a 100644 --- a/logic/net/LoginTask.cpp +++ b/logic/net/LoginTask.cpp @@ -264,6 +264,6 @@ void LoginTask::parseYggdrasilReply(QByteArray data) }; */ - result = {uInfo.username, sessionID, playerName, playerID}; + result = {uInfo.username, sessionID, playerName, playerID, accessToken}; emitSucceeded(); } diff --git a/logic/net/LoginTask.h b/logic/net/LoginTask.h index ba87142d..daea18af 100644 --- a/logic/net/LoginTask.h +++ b/logic/net/LoginTask.h @@ -27,9 +27,10 @@ struct UserInfo struct LoginResponse { QString username; - QString session_id; + QString session_id; // session id is a combination of player id and the access token QString player_name; QString player_id; + QString access_token; }; class QNetworkReply; -- cgit From c700b7be2e6e5632f6cea6f0c45744f494a0629f Mon Sep 17 00:00:00 2001 From: Sky Date: Thu, 17 Oct 2013 00:02:56 +0100 Subject: Un-copy-pasta the login response handler using std::function magic --- logic/net/LoginTask.cpp | 145 ++++++++++++++++++++---------------------------- logic/net/LoginTask.h | 2 + 2 files changed, 63 insertions(+), 84 deletions(-) (limited to 'logic/net/LoginTask.h') diff --git a/logic/net/LoginTask.cpp b/logic/net/LoginTask.cpp index 62d6331f..70ef2ae6 100644 --- a/logic/net/LoginTask.cpp +++ b/logic/net/LoginTask.cpp @@ -56,45 +56,6 @@ void LoginTask::legacyLogin() netReply = worker->post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); } -void LoginTask::processLegacyReply(QNetworkReply *reply) -{ - if (netReply != reply) - return; - // Check for errors. - switch (reply->error()) - { - case QNetworkReply::NoError: - { - // Check the response code. - int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (responseCode == 200) - { - parseLegacyReply(reply->readAll()); - } - else if (responseCode == 503) - { - emitFailed(tr("The login servers are currently unavailable. Check " - "http://help.mojang.com/ for more info.")); - } - else - { - emitFailed(tr("Login failed: Unknown HTTP error %1 occurred.") - .arg(QString::number(responseCode))); - } - break; - } - - case QNetworkReply::OperationCanceledError: - emitFailed(tr("Login canceled.")); - break; - - default: - emitFailed(tr("Login failed: %1").arg(reply->errorString())); - break; - } -} - void LoginTask::parseLegacyReply(QByteArray data) { QString responseStr = QString::fromUtf8(data); @@ -129,6 +90,67 @@ void LoginTask::parseLegacyReply(QByteArray data) } } +void LoginTask::processLegacyReply(QNetworkReply *reply) +{ + processReply(reply, &LoginTask::parseLegacyReply); +} + +void LoginTask::processYggdrasilReply(QNetworkReply *reply) +{ + processReply(reply, &LoginTask::parseYggdrasilReply); +} + +void LoginTask::processReply(QNetworkReply *reply, std::function parser) +{ + if (netReply != reply) + return; + // Check for errors. + switch (reply->error()) + { + case QNetworkReply::NoError: + { + // Check the response code. + int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + switch (responseCode) + { + case 200: + parser(this, reply->readAll()); + break; + + default: + emitFailed(tr("Login failed: Unknown HTTP code %1 encountered.").arg(responseCode)); + break; + } + + break; + } + + case QNetworkReply::OperationCanceledError: + emitFailed(tr("Login canceled.")); + break; + + default: + int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + + switch (responseCode) + { + case 403: + emitFailed(tr("Invalid username or password.")); + break; + + case 503: + emitFailed(tr("The login servers are currently unavailable. Check " + "http://help.mojang.com/ for more info.")); + break; + + default: + QLOG_DEBUG() << "Login failed with QNetworkReply code:" << reply->error(); + emitFailed(tr("Login failed: %1").arg(reply->errorString())); + break; + } + } +} void LoginTask::yggdrasilLogin() { @@ -168,51 +190,6 @@ void LoginTask::yggdrasilLogin() netReply = worker->post(netRequest, requestConstent.toUtf8()); } -void LoginTask::processYggdrasilReply(QNetworkReply *reply) -{ - if (netReply != reply) - return; - // Check for errors. - switch (reply->error()) - { - case QNetworkReply::NoError: - { - // Check the response code. - int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - - if (responseCode == 200) - { - parseYggdrasilReply(reply->readAll()); - } - else if (responseCode == 503) - { - emitFailed(tr("The login servers are currently unavailable. Check " - "http://help.mojang.com/ for more info.")); - } - else - { - emitFailed(tr("Login failed: Unknown HTTP error %1 occurred.") - .arg(QString::number(responseCode))); - } - break; - } - - case QNetworkReply::OperationCanceledError: - emitFailed(tr("Login canceled.")); - break; - - // Equivalent to an HTTP 403 - case QNetworkReply::ContentOperationNotPermittedError: - emitFailed(tr("Invalid username or password.")); - break; - - default: - QLOG_DEBUG() << "Login failed with QNetworkReply code:" << reply->error(); - emitFailed(tr("Login failed: %1").arg(reply->errorString())); - break; - } -} - /* { "accessToken": "random access token", // hexadecimal diff --git a/logic/net/LoginTask.h b/logic/net/LoginTask.h index daea18af..fa5897cb 100644 --- a/logic/net/LoginTask.h +++ b/logic/net/LoginTask.h @@ -54,6 +54,8 @@ protected slots: void processYggdrasilReply(QNetworkReply *reply); void parseYggdrasilReply(QByteArray data); + void processReply(QNetworkReply *reply, std::function); + protected: void executeTask(); -- cgit From a600286e33601a85949b9e51bd5421a45f9998ac Mon Sep 17 00:00:00 2001 From: Sky Date: Thu, 17 Oct 2013 00:46:25 +0100 Subject: Use Yggdrasil error response when available, or fall back to legacy HTTP error codes --- logic/net/LoginTask.cpp | 69 ++++++++++++++++++++++++++++++++++++------------- logic/net/LoginTask.h | 4 ++- 2 files changed, 54 insertions(+), 19 deletions(-) (limited to 'logic/net/LoginTask.h') diff --git a/logic/net/LoginTask.cpp b/logic/net/LoginTask.cpp index 70ef2ae6..4098783b 100644 --- a/logic/net/LoginTask.cpp +++ b/logic/net/LoginTask.cpp @@ -92,15 +92,15 @@ void LoginTask::parseLegacyReply(QByteArray data) void LoginTask::processLegacyReply(QNetworkReply *reply) { - processReply(reply, &LoginTask::parseLegacyReply); + processReply(reply, &LoginTask::parseLegacyReply, &LoginTask::parseLegacyError); } void LoginTask::processYggdrasilReply(QNetworkReply *reply) { - processReply(reply, &LoginTask::parseYggdrasilReply); + processReply(reply, &LoginTask::parseYggdrasilReply, &LoginTask::parseYggdrasilError); } -void LoginTask::processReply(QNetworkReply *reply, std::function parser) +void LoginTask::processReply(QNetworkReply *reply, std::function parser, std::function errorHandler) { if (netReply != reply) return; @@ -131,25 +131,58 @@ void LoginTask::processReply(QNetworkReply *reply, std::functionattribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); + emitFailed(errorHandler(this, reply)); + break; + } +} - switch (responseCode) - { - case 403: - emitFailed(tr("Invalid username or password.")); - break; +QString LoginTask::parseLegacyError(QNetworkReply *reply) +{ + int responseCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - case 503: - emitFailed(tr("The login servers are currently unavailable. Check " - "http://help.mojang.com/ for more info.")); - break; + switch (responseCode) + { + case 403: + return tr("Invalid username or password."); - default: - QLOG_DEBUG() << "Login failed with QNetworkReply code:" << reply->error(); - emitFailed(tr("Login failed: %1").arg(reply->errorString())); - break; - } + case 503: + return tr("The login servers are currently unavailable. Check " + "http://help.mojang.com/ for more info."); + + default: + QLOG_DEBUG() << "Login failed with QNetworkReply code:" << reply->error(); + return tr("Login failed: %1").arg(reply->errorString()); + } +} + +QString LoginTask::parseYggdrasilError(QNetworkReply *reply) +{ + QByteArray data = reply->readAll(); + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + + // If there are JSON errors fall back to using the legacy error handling using HTTP status codes + if (jsonError.error != QJsonParseError::NoError) + { + return parseLegacyError(reply); + } + + if (!jsonDoc.isObject()) + { + return parseLegacyError(reply); } + + QJsonObject root = jsonDoc.object(); + + //QString error = root.value("error").toString(); + QString errorMessage = root.value("errorMessage").toString(); + + if(errorMessage.isEmpty()) + { + return parseLegacyError(reply); + } + + return tr("Login failed: ") + errorMessage; } void LoginTask::yggdrasilLogin() diff --git a/logic/net/LoginTask.h b/logic/net/LoginTask.h index fa5897cb..aa925999 100644 --- a/logic/net/LoginTask.h +++ b/logic/net/LoginTask.h @@ -49,12 +49,14 @@ protected slots: void legacyLogin(); void processLegacyReply(QNetworkReply *reply); void parseLegacyReply(QByteArray data); + QString parseLegacyError(QNetworkReply *reply); void yggdrasilLogin(); void processYggdrasilReply(QNetworkReply *reply); void parseYggdrasilReply(QByteArray data); + QString parseYggdrasilError(QNetworkReply *reply); - void processReply(QNetworkReply *reply, std::function); + void processReply(QNetworkReply *reply, std::function, std::function); protected: void executeTask(); -- cgit