From 984c36e571aae45cdd55da2fb689538198aadd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 23 Sep 2013 00:23:50 +0200 Subject: Implement basic yggdrasil auth. No fancy login token saving involved. --- logic/BaseInstance.h | 3 +- logic/InstanceLauncher.cpp | 4 +- logic/LegacyInstance.cpp | 6 +- logic/LegacyInstance.h | 2 +- logic/MinecraftProcess.cpp | 83 +++++++------- logic/OneSixInstance.cpp | 20 ++-- logic/OneSixInstance.h | 4 +- logic/net/LoginTask.cpp | 269 +++++++++++++++++++++++++++++++++++++++++++++ logic/net/LoginTask.h | 62 +++++++++++ logic/tasks/LoginTask.cpp | 111 ------------------- logic/tasks/LoginTask.h | 58 ---------- 11 files changed, 392 insertions(+), 230 deletions(-) create mode 100644 logic/net/LoginTask.cpp create mode 100644 logic/net/LoginTask.h delete mode 100644 logic/tasks/LoginTask.cpp delete mode 100644 logic/tasks/LoginTask.h (limited to 'logic') diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 374d1437..0056327a 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -22,6 +22,7 @@ #include "inifile.h" #include "lists/BaseVersionList.h" +#include "net/LoginTask.h" class QDialog; class BaseUpdate; @@ -147,7 +148,7 @@ public: virtual BaseUpdate* doUpdate() = 0; /// returns a valid minecraft process, ready for launch - virtual MinecraftProcess* prepareForLaunch(QString user, QString session) = 0; + virtual MinecraftProcess* prepareForLaunch(LoginResponse response) = 0; /// do any necessary cleanups after the instance finishes. also runs before 'prepareForLaunch' virtual void cleanupAfterRun() = 0; diff --git a/logic/InstanceLauncher.cpp b/logic/InstanceLauncher.cpp index f2f792c9..93b87f23 100644 --- a/logic/InstanceLauncher.cpp +++ b/logic/InstanceLauncher.cpp @@ -5,7 +5,7 @@ #include "gui/logindialog.h" #include "gui/ProgressDialog.h" #include "gui/consolewindow.h" -#include "logic/tasks/LoginTask.h" +#include "logic/net/LoginTask.h" #include "logic/MinecraftProcess.h" #include "lists/InstanceList.h" @@ -25,7 +25,7 @@ void InstanceLauncher::onLoginComplete() LoginTask * task = ( LoginTask * ) QObject::sender(); auto result = task->getResult(); auto instance = MMC->instances()->getInstanceById(instId); - proc = instance->prepareForLaunch ( result.username, result.sessionID ); + proc = instance->prepareForLaunch ( result ); if ( !proc ) { //FIXME: report error diff --git a/logic/LegacyInstance.cpp b/logic/LegacyInstance.cpp index 0672d2c8..4f367980 100644 --- a/logic/LegacyInstance.cpp +++ b/logic/LegacyInstance.cpp @@ -29,7 +29,7 @@ BaseUpdate* LegacyInstance::doUpdate() return new LegacyUpdate(this, this); } -MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session) +MinecraftProcess* LegacyInstance::prepareForLaunch(LoginResponse response) { MinecraftProcess * proc = new MinecraftProcess(this); @@ -73,8 +73,8 @@ MinecraftProcess* LegacyInstance::prepareForLaunch(QString user, QString session args << QString("-Xmx%1m").arg(settings().get("MaxMemAlloc").toInt()); args << QString("-XX:PermSize=%1m").arg(settings().get("PermGen").toInt()); args << "-jar" << LAUNCHER_FILE; - args << user; - args << session; + args << response.player_name; + args << response.session_id; args << windowTitle; args << windowSize; args << lwjgl; diff --git a/logic/LegacyInstance.h b/logic/LegacyInstance.h index b36026fc..2eab9035 100644 --- a/logic/LegacyInstance.h +++ b/logic/LegacyInstance.h @@ -57,7 +57,7 @@ public: virtual void setShouldUpdate(bool val); virtual BaseUpdate* doUpdate(); - virtual MinecraftProcess* prepareForLaunch( QString user, QString session ); + virtual MinecraftProcess* prepareForLaunch(LoginResponse response); virtual void cleanupAfterRun(); virtual QDialog * createModEditDialog ( QWidget* parent ); diff --git a/logic/MinecraftProcess.cpp b/logic/MinecraftProcess.cpp index 299f00be..06b7a1f1 100644 --- a/logic/MinecraftProcess.cpp +++ b/logic/MinecraftProcess.cpp @@ -32,46 +32,45 @@ #define IBUS "@im=ibus" // constructor -MinecraftProcess::MinecraftProcess( BaseInstance* inst ) : - m_instance(inst) +MinecraftProcess::MinecraftProcess(BaseInstance *inst) : m_instance(inst) { - connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(finish(int, QProcess::ExitStatus))); - + connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(finish(int, QProcess::ExitStatus))); + // prepare the process environment QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - + #ifdef LINUX // Strip IBus if (env.value("XMODIFIERS").contains(IBUS)) env.insert("XMODIFIERS", env.value("XMODIFIERS").replace(IBUS, "")); #endif - + // export some infos env.insert("INST_NAME", inst->name()); env.insert("INST_ID", inst->id()); env.insert("INST_DIR", QDir(inst->instanceRoot()).absolutePath()); - + this->setProcessEnvironment(env); m_prepostlaunchprocess.setProcessEnvironment(env); - + // std channels connect(this, SIGNAL(readyReadStandardError()), SLOT(on_stdErr())); connect(this, SIGNAL(readyReadStandardOutput()), SLOT(on_stdOut())); } -void MinecraftProcess::setMinecraftArguments ( QStringList args ) +void MinecraftProcess::setMinecraftArguments(QStringList args) { m_args = args; } -void MinecraftProcess::setMinecraftWorkdir ( QString path ) +void MinecraftProcess::setMinecraftWorkdir(QString path) { QDir mcDir(path); this->setWorkingDirectory(mcDir.absolutePath()); m_prepostlaunchprocess.setWorkingDirectory(mcDir.absolutePath()); } - // console window void MinecraftProcess::on_stdErr() { @@ -80,18 +79,17 @@ void MinecraftProcess::on_stdErr() m_err_leftover.clear(); QStringList lines = str.split("\n"); bool complete = str.endsWith("\n"); - - for(int i = 0; i < lines.size() - 1; i++) + + for (int i = 0; i < lines.size() - 1; i++) { - QString & line = lines[i]; - emit log(line.replace(username, "").replace(sessionID, "").toLocal8Bit(), getLevel(line, MessageLevel::Error)); + QString &line = lines[i]; + emit log(line /*.replace(username, "").replace(sessionID, "")*/, + getLevel(line, MessageLevel::Error)); } - if(!complete) + if (!complete) m_err_leftover = lines.last(); } - - void MinecraftProcess::on_stdOut() { QByteArray data = readAllStandardOutput(); @@ -99,13 +97,14 @@ void MinecraftProcess::on_stdOut() m_out_leftover.clear(); QStringList lines = str.split("\n"); bool complete = str.endsWith("\n"); - - for(int i = 0; i < lines.size() - 1; i++) + + for (int i = 0; i < lines.size() - 1; i++) { - QString & line = lines[i]; - emit log(line.replace(username, "").replace(sessionID, "").toLocal8Bit(), getLevel(line, MessageLevel::Message)); + QString &line = lines[i]; + emit log(line /*.replace(username, "").replace(sessionID, "")*/, + getLevel(line, MessageLevel::Message)); } - if(!complete) + if (!complete) m_out_leftover = lines.last(); } @@ -114,20 +113,20 @@ void MinecraftProcess::finish(int code, ExitStatus status) { if (status != NormalExit) { - //TODO: error handling + // TODO: error handling } - + // TODO: Localization - + if (!killed) //: Message displayed on instance exit emit log(tr("Minecraft exited with exitcode %1.").arg(status)); else //: Message displayed after the instance exits due to kill request emit log(tr("Minecraft was killed by user."), MessageLevel::Error); - + m_prepostlaunchprocess.processEnvironment().insert("INST_EXITCODE", QString(code)); - + // run post-exit if (!m_instance->settings().get("PostExitCommand").toString().isEmpty()) { @@ -135,7 +134,7 @@ void MinecraftProcess::finish(int code, ExitStatus status) m_prepostlaunchprocess.waitForFinished(); if (m_prepostlaunchprocess.exitStatus() != NormalExit) { - //TODO: error handling + // TODO: error handling } } m_instance->cleanupAfterRun(); @@ -156,40 +155,42 @@ void MinecraftProcess::launch() m_prepostlaunchprocess.waitForFinished(); if (m_prepostlaunchprocess.exitStatus() != NormalExit) { - //TODO: error handling + // TODO: error handling return; } } - + m_instance->setLastLaunch(); - + emit log(QString("Minecraft folder is: '%1'").arg(workingDirectory())); QString JavaPath = m_instance->settings().get("JavaPath").toString(); emit log(QString("Java path: '%1'").arg(JavaPath)); - emit log(QString("Arguments: '%1'").arg(m_args.join("' '").replace(username, "").replace(sessionID, ""))); + emit log(QString("Arguments: '%1'").arg( + m_args.join("' '") /*.replace(username, "").replace(sessionID, "")*/)); start(JavaPath, m_args); if (!waitForStarted()) { //: Error message displayed if instace can't start emit log(tr("Could not launch minecraft!")); return; - //TODO: error handling + // TODO: error handling } } MessageLevel::Enum MinecraftProcess::getLevel(const QString &line, MessageLevel::Enum level) { - - if(line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || line.contains("[FINER]") || line.contains("[FINEST]") ) + + if (line.contains("[INFO]") || line.contains("[CONFIG]") || line.contains("[FINE]") || + line.contains("[FINER]") || line.contains("[FINEST]")) level = MessageLevel::Message; - if(line.contains("[SEVERE]") || line.contains("[STDERR]")) + if (line.contains("[SEVERE]") || line.contains("[STDERR]")) level = MessageLevel::Error; - if(line.contains("[WARNING]")) + if (line.contains("[WARNING]")) level = MessageLevel::Warning; - if(line.contains("Exception in thread") || line.contains(" at ")) + if (line.contains("Exception in thread") || line.contains(" at ")) level = MessageLevel::Fatal; - if(line.contains("[DEBUG]")) + if (line.contains("[DEBUG]")) level = MessageLevel::Debug; return level; - } \ No newline at end of file diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp index e22a8890..6e39b5b5 100644 --- a/logic/OneSixInstance.cpp +++ b/logic/OneSixInstance.cpp @@ -49,21 +49,19 @@ QString replaceTokensIn(QString text, QMap with) return result; } -QStringList OneSixInstance::processMinecraftArgs(QString user, QString session) +QStringList OneSixInstance::processMinecraftArgs(LoginResponse response) { I_D(OneSixInstance); auto version = d->version; QString args_pattern = version->minecraftArguments; QMap token_mapping; - token_mapping["auth_username"] = user; - token_mapping["auth_session"] = session; - // FIXME: user and player name are DIFFERENT! - token_mapping["auth_player_name"] = user; - // FIXME: WTF is this. I just plugged in a random UUID here. - token_mapping["auth_uuid"] = "7d4bacf0-fd62-11e2-b778-0800200c9a66"; // obviously fake. - - // this is for offline: + token_mapping["auth_username"] = response.username; + token_mapping["auth_session"] = response.session_id; + token_mapping["auth_player_name"] = response.player_name; + token_mapping["auth_uuid"] = response.player_id; + + // this is for offline?: /* map["auth_player_name"] = "Player"; map["auth_player_name"] = "00000000-0000-0000-0000-000000000000"; @@ -85,7 +83,7 @@ QStringList OneSixInstance::processMinecraftArgs(QString user, QString session) return parts; } -MinecraftProcess *OneSixInstance::prepareForLaunch(QString user, QString session) +MinecraftProcess *OneSixInstance::prepareForLaunch(LoginResponse response) { I_D(OneSixInstance); cleanupAfterRun(); @@ -142,7 +140,7 @@ MinecraftProcess *OneSixInstance::prepareForLaunch(QString user, QString session args << classPath; } args << version->mainClass; - args.append(processMinecraftArgs(user, session)); + args.append(processMinecraftArgs(response)); // create the process and set its parameters MinecraftProcess *proc = new MinecraftProcess(this); diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h index 0139b645..33091188 100644 --- a/logic/OneSixInstance.h +++ b/logic/OneSixInstance.h @@ -23,7 +23,7 @@ public: virtual QString instanceConfigFolder() const; virtual BaseUpdate* doUpdate(); - virtual MinecraftProcess* prepareForLaunch ( QString user, QString session ); + virtual MinecraftProcess* prepareForLaunch ( LoginResponse response ); virtual void cleanupAfterRun(); virtual QString intendedVersionId() const; @@ -54,5 +54,5 @@ public: virtual bool menuActionEnabled ( QString action_name ) const; virtual QString getStatusbarDescription(); private: - QStringList processMinecraftArgs( QString user, QString session ); + QStringList processMinecraftArgs( LoginResponse response ); }; \ No newline at end of file diff --git a/logic/net/LoginTask.cpp b/logic/net/LoginTask.cpp new file mode 100644 index 00000000..2a45400e --- /dev/null +++ b/logic/net/LoginTask.cpp @@ -0,0 +1,269 @@ +/* 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. + */ + +#include "LoginTask.h" +#include "MultiMC.h" +#include + +#include + +#include +#include + +#include +#include +#include +#include + +LoginTask::LoginTask(const UserInfo &uInfo, QObject *parent) : Task(parent), uInfo(uInfo) +{ +} + +void LoginTask::executeTask() +{ + yggdrasilLogin(); +} + +void LoginTask::legacyLogin() +{ + setStatus(tr("Logging in...")); + auto worker = MMC->qnam(); + connect(worker.data(), SIGNAL(finished(QNetworkReply *)), this, + SLOT(processLegacyReply(QNetworkReply *))); + + QUrl loginURL("https://login.minecraft.net/"); + QNetworkRequest netRequest(loginURL); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, + "application/x-www-form-urlencoded"); + + QUrlQuery params; + params.addQueryItem("user", uInfo.username); + params.addQueryItem("password", uInfo.password); + params.addQueryItem("version", "13"); + + 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); + + QStringList strings = responseStr.split(":"); + if (strings.count() >= 4) + { + // strings[1] is the download ticket. It isn't used anymore. + QString username = strings[2]; + QString sessionID = strings[3]; + /* + struct LoginResponse + { + QString username; + QString session_id; + QString player_name; + QString player_id; + QString client_id; + }; + */ + result = {username, sessionID, username, QString()}; + emitSucceeded(); + } + else + { + if (responseStr.toLower() == "bad login") + emitFailed(tr("Invalid username or password.")); + else if (responseStr.toLower() == "old version") + emitFailed(tr("Launcher outdated, please update.")); + else + emitFailed(tr("Login failed: %1").arg(responseStr)); + } +} + + +void LoginTask::yggdrasilLogin() +{ + setStatus(tr("Logging in...")); + auto worker = MMC->qnam(); + connect(worker.data(), SIGNAL(finished(QNetworkReply *)), this, + SLOT(processYggdrasilReply(QNetworkReply *))); + + /* + { + // agent def. version might be incremented at some point + "agent":{"name":"Minecraft","version":1}, + "username": "mojang account name", + "password": "mojang account password", + // client token is optional. but we supply one anyway + "clientToken": "client identifier" + } + */ + + QUrl loginURL("https://authserver.mojang.com/authenticate"); + QNetworkRequest netRequest(loginURL); + netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + auto settings = MMC->settings(); + QString clientToken = settings->get("YggdrasilClientToken").toString(); + // escape the {} + clientToken.remove('{'); + clientToken.remove('}'); + // create the request + QString requestConstent; + requestConstent += "{"; + requestConstent += " \"agent\":{\"name\":\"Minecraft\",\"version\":1},\n"; + requestConstent += " \"username\":\"" + uInfo.username + "\",\n"; + requestConstent += " \"password\":\"" + uInfo.password + "\",\n"; + requestConstent += " \"clientToken\":\"" + clientToken + "\"\n"; + requestConstent += "}"; + 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; + + default: + emitFailed(tr("Login failed: %1").arg(reply->errorString())); + break; + } +} + +/* +{ + "accessToken": "random access token", // hexadecimal + "clientToken": "client identifier", // identical to the one received + "availableProfiles": [ // only present if the agent field was received + { + "id": "profile identifier", // hexadecimal + "name": "player name" + } + ], + "selectedProfile": { // only present if the agent field was received + "id": "profile identifier", + "name": "player name" + } +} +*/ +void LoginTask::parseYggdrasilReply(QByteArray data) +{ + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError); + if (jsonError.error != QJsonParseError::NoError) + { + emitFailed(tr("Login failed: %1").arg(jsonError.errorString())); + return; + } + + if (!jsonDoc.isObject()) + { + emitFailed(tr("Login failed: BAD FORMAT #1")); + return; + } + + QJsonObject root = jsonDoc.object(); + + QString accessToken = root.value("accessToken").toString(); + QString clientToken = root.value("clientToken").toString(); + QString playerID; + QString playerName; + auto selectedProfile = root.value("selectedProfile"); + if(selectedProfile.isObject()) + { + auto selectedProfileO = selectedProfile.toObject(); + playerID = selectedProfileO.value("id").toString(); + playerName = selectedProfileO.value("name").toString(); + } + QString sessionID = "token:" + accessToken + ":" + playerID; + /* + struct LoginResponse + { + QString username; + QString session_id; + QString player_name; + QString player_id; + QString client_id; + }; + */ + + result = {uInfo.username, sessionID, playerName, playerID}; + emitSucceeded(); +} 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; +}; diff --git a/logic/tasks/LoginTask.cpp b/logic/tasks/LoginTask.cpp deleted file mode 100644 index 222af618..00000000 --- a/logic/tasks/LoginTask.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* 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. - */ - -#include "LoginTask.h" -#include "MultiMC.h" - -#include - -#include -#include - -#include -#include - -LoginTask::LoginTask( const UserInfo& uInfo, QObject* parent ) : Task(parent), uInfo(uInfo){} - -void LoginTask::executeTask() -{ - setStatus(tr("Logging in...")); - auto worker = MMC->qnam(); - connect(worker.data(), SIGNAL(finished(QNetworkReply*)), this, SLOT(processNetReply(QNetworkReply*))); - - QUrl loginURL("https://login.minecraft.net/"); - QNetworkRequest netRequest(loginURL); - netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); - - QUrlQuery params; - params.addQueryItem("user", uInfo.username); - params.addQueryItem("password", uInfo.password); - params.addQueryItem("version", "13"); - - netReply = worker->post(netRequest, params.query(QUrl::EncodeSpaces).toUtf8()); -} - -void LoginTask::processNetReply(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) - { - QString responseStr(reply->readAll()); - - QStringList strings = responseStr.split(":"); - if (strings.count() >= 4) - { - bool parseSuccess; - qint64 latestVersion = strings[0].toLongLong(&parseSuccess); - if (parseSuccess) - { - // strings[1] is the download ticket. It isn't used anymore. - QString username = strings[2]; - QString sessionID = strings[3]; - - result = {username, sessionID, latestVersion}; - emitSucceeded(); - } - else - { - emitFailed(tr("Failed to parse Minecraft version string.")); - } - } - else - { - if (responseStr.toLower() == "bad login") - emitFailed(tr("Invalid username or password.")); - else if (responseStr.toLower() == "old version") - emitFailed(tr("Launcher outdated, please update.")); - else - emitFailed(tr("Login failed: %1").arg(responseStr)); - } - } - 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; - } -} diff --git a/logic/tasks/LoginTask.h b/logic/tasks/LoginTask.h deleted file mode 100644 index bde672b8..00000000 --- a/logic/tasks/LoginTask.h +++ /dev/null @@ -1,58 +0,0 @@ -/* 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. - */ - -#ifndef LOGINTASK_H -#define LOGINTASK_H - -#include "Task.h" -#include - -struct UserInfo -{ - QString username; - QString password; -}; - -struct LoginResponse -{ - QString username; - QString sessionID; - qint64 latestVersion; -}; - -class QNetworkReply; - -class LoginTask : public Task -{ - Q_OBJECT -public: - explicit LoginTask(const UserInfo& uInfo, QObject *parent = 0); - LoginResponse getResult() - { - return result; - }; - -protected slots: - void processNetReply(QNetworkReply* reply); - -protected: - void executeTask(); - - LoginResponse result; - QNetworkReply* netReply; - UserInfo uInfo; -}; - -#endif // LOGINTASK_H -- cgit v1.2.3