summaryrefslogtreecommitdiffstats
path: root/logic/auth
diff options
context:
space:
mode:
Diffstat (limited to 'logic/auth')
-rw-r--r--logic/auth/AuthSession.cpp30
-rw-r--r--logic/auth/AuthSession.h51
-rw-r--r--logic/auth/MojangAccount.cpp278
-rw-r--r--logic/auth/MojangAccount.h173
-rw-r--r--logic/auth/MojangAccountList.cpp427
-rw-r--r--logic/auth/MojangAccountList.h201
-rw-r--r--logic/auth/YggdrasilTask.cpp254
-rw-r--r--logic/auth/YggdrasilTask.h150
-rw-r--r--logic/auth/flows/AuthenticateTask.cpp203
-rw-r--r--logic/auth/flows/AuthenticateTask.h46
-rw-r--r--logic/auth/flows/RefreshTask.cpp145
-rw-r--r--logic/auth/flows/RefreshTask.h44
-rw-r--r--logic/auth/flows/ValidateTask.cpp62
-rw-r--r--logic/auth/flows/ValidateTask.h47
14 files changed, 0 insertions, 2111 deletions
diff --git a/logic/auth/AuthSession.cpp b/logic/auth/AuthSession.cpp
deleted file mode 100644
index 8758bfbd..00000000
--- a/logic/auth/AuthSession.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#include "AuthSession.h"
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QJsonDocument>
-#include <QStringList>
-
-QString AuthSession::serializeUserProperties()
-{
- QJsonObject userAttrs;
- for (auto key : u.properties.keys())
- {
- auto array = QJsonArray::fromStringList(u.properties.values(key));
- userAttrs.insert(key, array);
- }
- QJsonDocument value(userAttrs);
- return value.toJson(QJsonDocument::Compact);
-
-}
-
-bool AuthSession::MakeOffline(QString offline_playername)
-{
- if (status != PlayableOffline && status != PlayableOnline)
- {
- return false;
- }
- session = "-";
- player_name = offline_playername;
- status = PlayableOffline;
- return true;
-}
diff --git a/logic/auth/AuthSession.h b/logic/auth/AuthSession.h
deleted file mode 100644
index dede90a9..00000000
--- a/logic/auth/AuthSession.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include <QString>
-#include <QMultiMap>
-#include <memory>
-
-#include "multimc_logic_export.h"
-
-struct User
-{
- QString id;
- QMultiMap<QString, QString> properties;
-};
-
-struct MULTIMC_LOGIC_EXPORT AuthSession
-{
- bool MakeOffline(QString offline_playername);
-
- QString serializeUserProperties();
-
- enum Status
- {
- Undetermined,
- RequiresPassword,
- PlayableOffline,
- PlayableOnline
- } status = Undetermined;
-
- User u;
-
- // client token
- QString client_token;
- // account user name
- QString username;
- // combined session ID
- QString session;
- // volatile auth token
- QString access_token;
- // profile name
- QString player_name;
- // profile ID
- QString uuid;
- // 'legacy' or 'mojang', depending on account type
- QString user_type;
- // Did the auth server reply?
- bool auth_server_online = false;
- // Did the user request online mode?
- bool wants_online = true;
-};
-
-typedef std::shared_ptr<AuthSession> AuthSessionPtr;
diff --git a/logic/auth/MojangAccount.cpp b/logic/auth/MojangAccount.cpp
deleted file mode 100644
index 69a24c09..00000000
--- a/logic/auth/MojangAccount.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/* Copyright 2013-2015 MultiMC Contributors
- *
- * Authors: Orochimarufan <orochimarufan.x3@gmail.com>
- *
- * 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 "MojangAccount.h"
-#include "flows/RefreshTask.h"
-#include "flows/AuthenticateTask.h"
-
-#include <QUuid>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QRegExp>
-#include <QStringList>
-#include <QJsonDocument>
-
-#include <QDebug>
-
-MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
-{
- // The JSON object must at least have a username for it to be valid.
- if (!object.value("username").isString())
- {
- qCritical() << "Can't load Mojang account info from JSON object. Username field is "
- "missing or of the wrong type.";
- return nullptr;
- }
-
- QString username = object.value("username").toString("");
- QString clientToken = object.value("clientToken").toString("");
- QString accessToken = object.value("accessToken").toString("");
-
- QJsonArray profileArray = object.value("profiles").toArray();
- if (profileArray.size() < 1)
- {
- qCritical() << "Can't load Mojang account with username \"" << username
- << "\". No profiles found.";
- return nullptr;
- }
-
- QList<AccountProfile> profiles;
- for (QJsonValue profileVal : profileArray)
- {
- QJsonObject profileObject = profileVal.toObject();
- QString id = profileObject.value("id").toString("");
- QString name = profileObject.value("name").toString("");
- bool legacy = profileObject.value("legacy").toBool(false);
- if (id.isEmpty() || name.isEmpty())
- {
- qWarning() << "Unable to load a profile because it was missing an ID or a name.";
- continue;
- }
- profiles.append({id, name, legacy});
- }
-
- MojangAccountPtr account(new MojangAccount());
- if (object.value("user").isObject())
- {
- User u;
- QJsonObject userStructure = object.value("user").toObject();
- u.id = userStructure.value("id").toString();
- /*
- QJsonObject propMap = userStructure.value("properties").toObject();
- for(auto key: propMap.keys())
- {
- auto values = propMap.operator[](key).toArray();
- for(auto value: values)
- u.properties.insert(key, value.toString());
- }
- */
- account->m_user = u;
- }
- account->m_username = username;
- account->m_clientToken = clientToken;
- account->m_accessToken = accessToken;
- account->m_profiles = profiles;
-
- // Get the currently selected profile.
- QString currentProfile = object.value("activeProfile").toString("");
- if (!currentProfile.isEmpty())
- account->setCurrentProfile(currentProfile);
-
- return account;
-}
-
-MojangAccountPtr MojangAccount::createFromUsername(const QString &username)
-{
- MojangAccountPtr account(new MojangAccount());
- account->m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
- account->m_username = username;
- return account;
-}
-
-QJsonObject MojangAccount::saveToJson() const
-{
- QJsonObject json;
- json.insert("username", m_username);
- json.insert("clientToken", m_clientToken);
- json.insert("accessToken", m_accessToken);
-
- QJsonArray profileArray;
- for (AccountProfile profile : m_profiles)
- {
- QJsonObject profileObj;
- profileObj.insert("id", profile.id);
- profileObj.insert("name", profile.name);
- profileObj.insert("legacy", profile.legacy);
- profileArray.append(profileObj);
- }
- json.insert("profiles", profileArray);
-
- QJsonObject userStructure;
- {
- userStructure.insert("id", m_user.id);
- /*
- QJsonObject userAttrs;
- for(auto key: m_user.properties.keys())
- {
- auto array = QJsonArray::fromStringList(m_user.properties.values(key));
- userAttrs.insert(key, array);
- }
- userStructure.insert("properties", userAttrs);
- */
- }
- json.insert("user", userStructure);
-
- if (m_currentProfile != -1)
- json.insert("activeProfile", currentProfile()->id);
-
- return json;
-}
-
-bool MojangAccount::setCurrentProfile(const QString &profileId)
-{
- for (int i = 0; i < m_profiles.length(); i++)
- {
- if (m_profiles[i].id == profileId)
- {
- m_currentProfile = i;
- return true;
- }
- }
- return false;
-}
-
-const AccountProfile *MojangAccount::currentProfile() const
-{
- if (m_currentProfile == -1)
- return nullptr;
- return &m_profiles[m_currentProfile];
-}
-
-AccountStatus MojangAccount::accountStatus() const
-{
- if (m_accessToken.isEmpty())
- return NotVerified;
- else
- return Verified;
-}
-
-std::shared_ptr<YggdrasilTask> MojangAccount::login(AuthSessionPtr session,
- QString password)
-{
- Q_ASSERT(m_currentTask.get() == nullptr);
-
- // take care of the true offline status
- if (accountStatus() == NotVerified && password.isEmpty())
- {
- if (session)
- {
- session->status = AuthSession::RequiresPassword;
- fillSession(session);
- }
- return nullptr;
- }
-
- if (password.isEmpty())
- {
- m_currentTask.reset(new RefreshTask(this));
- }
- else
- {
- m_currentTask.reset(new AuthenticateTask(this, password));
- }
- m_currentTask->assignSession(session);
-
- connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
- connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
- return m_currentTask;
-}
-
-void MojangAccount::authSucceeded()
-{
- auto session = m_currentTask->getAssignedSession();
- if (session)
- {
- session->status =
- session->wants_online ? AuthSession::PlayableOnline : AuthSession::PlayableOffline;
- fillSession(session);
- session->auth_server_online = true;
- }
- m_currentTask.reset();
- emit changed();
-}
-
-void MojangAccount::authFailed(QString reason)
-{
- auto session = m_currentTask->getAssignedSession();
- // This is emitted when the yggdrasil tasks time out or are cancelled.
- // -> we treat the error as no-op
- if (m_currentTask->state() == YggdrasilTask::STATE_FAILED_SOFT)
- {
- if (session)
- {
- session->status = accountStatus() == Verified ? AuthSession::PlayableOffline
- : AuthSession::RequiresPassword;
- session->auth_server_online = false;
- fillSession(session);
- }
- }
- else
- {
- m_accessToken = QString();
- emit changed();
- if (session)
- {
- session->status = AuthSession::RequiresPassword;
- session->auth_server_online = true;
- fillSession(session);
- }
- }
- m_currentTask.reset();
-}
-
-void MojangAccount::fillSession(AuthSessionPtr session)
-{
- // the user name. you have to have an user name
- session->username = m_username;
- // volatile auth token
- session->access_token = m_accessToken;
- // the semi-permanent client token
- session->client_token = m_clientToken;
- if (currentProfile())
- {
- // profile name
- session->player_name = currentProfile()->name;
- // profile ID
- session->uuid = currentProfile()->id;
- // 'legacy' or 'mojang', depending on account type
- session->user_type = currentProfile()->legacy ? "legacy" : "mojang";
- if (!session->access_token.isEmpty())
- {
- session->session = "token:" + m_accessToken + ":" + m_profiles[m_currentProfile].id;
- }
- else
- {
- session->session = "-";
- }
- }
- else
- {
- session->player_name = "Player";
- session->session = "-";
- }
- session->u = user();
-}
diff --git a/logic/auth/MojangAccount.h b/logic/auth/MojangAccount.h
deleted file mode 100644
index 2de0c19c..00000000
--- a/logic/auth/MojangAccount.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/* Copyright 2013-2015 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 <QObject>
-#include <QString>
-#include <QList>
-#include <QJsonObject>
-#include <QPair>
-#include <QMap>
-
-#include <memory>
-#include "AuthSession.h"
-
-#include "multimc_logic_export.h"
-
-class Task;
-class YggdrasilTask;
-class MojangAccount;
-
-typedef std::shared_ptr<MojangAccount> MojangAccountPtr;
-Q_DECLARE_METATYPE(MojangAccountPtr)
-
-/**
- * A profile within someone's Mojang account.
- *
- * Currently, the profile system has not been implemented by Mojang yet,
- * but we might as well add some things for it in MultiMC right now so
- * we don't have to rip the code to pieces to add it later.
- */
-struct AccountProfile
-{
- QString id;
- QString name;
- bool legacy;
-};
-
-enum AccountStatus
-{
- NotVerified,
- Verified
-};
-
-/**
- * Object that stores information about a certain Mojang account.
- *
- * Said information may include things such as that account's username, client token, and access
- * token if the user chose to stay logged in.
- */
-class MULTIMC_LOGIC_EXPORT MojangAccount : public QObject
-{
- Q_OBJECT
-public: /* construction */
- //! Do not copy accounts. ever.
- explicit MojangAccount(const MojangAccount &other, QObject *parent) = delete;
-
- //! Default constructor
- explicit MojangAccount(QObject *parent = 0) : QObject(parent) {};
-
- //! Creates an empty account for the specified user name.
- static MojangAccountPtr createFromUsername(const QString &username);
-
- //! Loads a MojangAccount from the given JSON object.
- static MojangAccountPtr loadFromJson(const QJsonObject &json);
-
- //! Saves a MojangAccount to a JSON object and returns it.
- QJsonObject saveToJson() const;
-
-public: /* manipulation */
- /**
- * Sets the currently selected profile to the profile with the given ID string.
- * If profileId is not in the list of available profiles, the function will simply return
- * false.
- */
- bool setCurrentProfile(const QString &profileId);
-
- /**
- * Attempt to login. Empty password means we use the token.
- * If the attempt fails because we already are performing some task, it returns false.
- */
- std::shared_ptr<YggdrasilTask> login(AuthSessionPtr session,
- QString password = QString());
-
-public: /* queries */
- const QString &username() const
- {
- return m_username;
- }
-
- const QString &clientToken() const
- {
- return m_clientToken;
- }
-
- const QString &accessToken() const
- {
- return m_accessToken;
- }
-
- const QList<AccountProfile> &profiles() const
- {
- return m_profiles;
- }
-
- const User &user()
- {
- return m_user;
- }
-
- //! Returns the currently selected profile (if none, returns nullptr)
- const AccountProfile *currentProfile() const;
-
- //! Returns whether the account is NotVerified, Verified or Online
- AccountStatus accountStatus() const;
-
-signals:
- /**
- * This signal is emitted when the account changes
- */
- void changed();
-
- // TODO: better signalling for the various possible state changes - especially errors
-
-protected: /* variables */
- QString m_username;
-
- // Used to identify the client - the user can have multiple clients for the same account
- // Think: different launchers, all connecting to the same account/profile
- QString m_clientToken;
-
- // Blank if not logged in.
- QString m_accessToken;
-
- // Index of the selected profile within the list of available
- // profiles. -1 if nothing is selected.
- int m_currentProfile = -1;
-
- // List of available profiles.
- QList<AccountProfile> m_profiles;
-
- // the user structure, whatever it is.
- User m_user;
-
- // current task we are executing here
- std::shared_ptr<YggdrasilTask> m_currentTask;
-
-private
-slots:
- void authSucceeded();
- void authFailed(QString reason);
-
-private:
- void fillSession(AuthSessionPtr session);
-
-public:
- friend class YggdrasilTask;
- friend class AuthenticateTask;
- friend class ValidateTask;
- friend class RefreshTask;
-};
diff --git a/logic/auth/MojangAccountList.cpp b/logic/auth/MojangAccountList.cpp
deleted file mode 100644
index dac3d67f..00000000
--- a/logic/auth/MojangAccountList.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/* Copyright 2013-2015 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 "auth/MojangAccountList.h"
-
-#include <QIODevice>
-#include <QFile>
-#include <QTextStream>
-#include <QJsonDocument>
-#include <QJsonArray>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QDir>
-
-#include <QDebug>
-
-#include "auth/MojangAccount.h"
-#include <FileSystem.h>
-
-#define ACCOUNT_LIST_FORMAT_VERSION 2
-
-MojangAccountList::MojangAccountList(QObject *parent) : QAbstractListModel(parent)
-{
-}
-
-MojangAccountPtr MojangAccountList::findAccount(const QString &username) const
-{
- for (int i = 0; i < count(); i++)
- {
- MojangAccountPtr account = at(i);
- if (account->username() == username)
- return account;
- }
- return nullptr;
-}
-
-const MojangAccountPtr MojangAccountList::at(int i) const
-{
- return MojangAccountPtr(m_accounts.at(i));
-}
-
-void MojangAccountList::addAccount(const MojangAccountPtr account)
-{
- beginResetModel();
- connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
- m_accounts.append(account);
- endResetModel();
- onListChanged();
-}
-
-void MojangAccountList::removeAccount(const QString &username)
-{
- beginResetModel();
- for (auto account : m_accounts)
- {
- if (account->username() == username)
- {
- m_accounts.removeOne(account);
- return;
- }
- }
- endResetModel();
- onListChanged();
-}
-
-void MojangAccountList::removeAccount(QModelIndex index)
-{
- beginResetModel();
- m_accounts.removeAt(index.row());
- endResetModel();
- onListChanged();
-}
-
-MojangAccountPtr MojangAccountList::activeAccount() const
-{
- return m_activeAccount;
-}
-
-void MojangAccountList::setActiveAccount(const QString &username)
-{
- beginResetModel();
- if (username.isEmpty())
- {
- m_activeAccount = nullptr;
- }
- else
- {
- for (MojangAccountPtr account : m_accounts)
- {
- if (account->username() == username)
- m_activeAccount = account;
- }
- }
- endResetModel();
- onActiveChanged();
-}
-
-void MojangAccountList::accountChanged()
-{
- // the list changed. there is no doubt.
- onListChanged();
-}
-
-void MojangAccountList::onListChanged()
-{
- if (m_autosave)
- // TODO: Alert the user if this fails.
- saveList();
-
- emit listChanged();
-}
-
-void MojangAccountList::onActiveChanged()
-{
- if (m_autosave)
- saveList();
-
- emit activeAccountChanged();
-}
-
-int MojangAccountList::count() const
-{
- return m_accounts.count();
-}
-
-QVariant MojangAccountList::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- if (index.row() > count())
- return QVariant();
-
- MojangAccountPtr account = at(index.row());
-
- switch (role)
- {
- case Qt::DisplayRole:
- switch (index.column())
- {
- case NameColumn:
- return account->username();
-
- default:
- return QVariant();
- }
-
- case Qt::ToolTipRole:
- return account->username();
-
- case PointerRole:
- return qVariantFromValue(account);
-
- case Qt::CheckStateRole:
- switch (index.column())
- {
- case ActiveColumn:
- return account == m_activeAccount;
- }
-
- default:
- return QVariant();
- }
-}
-
-QVariant MojangAccountList::headerData(int section, Qt::Orientation orientation, int role) const
-{
- switch (role)
- {
- case Qt::DisplayRole:
- switch (section)
- {
- case ActiveColumn:
- return tr("Active?");
-
- case NameColumn:
- return tr("Name");
-
- default:
- return QVariant();
- }
-
- case Qt::ToolTipRole:
- switch (section)
- {
- case NameColumn:
- return tr("The name of the version.");
-
- default:
- return QVariant();
- }
-
- default:
- return QVariant();
- }
-}
-
-int MojangAccountList::rowCount(const QModelIndex &parent) const
-{
- // Return count
- return count();
-}
-
-int MojangAccountList::columnCount(const QModelIndex &parent) const
-{
- return 2;
-}
-
-Qt::ItemFlags MojangAccountList::flags(const QModelIndex &index) const
-{
- if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
- {
- return Qt::NoItemFlags;
- }
-
- return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
-}
-
-bool MojangAccountList::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
- {
- return false;
- }
-
- if(role == Qt::CheckStateRole)
- {
- if(value == Qt::Checked)
- {
- MojangAccountPtr account = this->at(index.row());
- this->setActiveAccount(account->username());
- }
- }
-
- emit dataChanged(index, index);
- return true;
-}
-
-void MojangAccountList::updateListData(QList<MojangAccountPtr> versions)
-{
- beginResetModel();
- m_accounts = versions;
- endResetModel();
-}
-
-bool MojangAccountList::loadList(const QString &filePath)
-{
- QString path = filePath;
- if (path.isEmpty())
- path = m_listFilePath;
- if (path.isEmpty())
- {
- qCritical() << "Can't load Mojang account list. No file path given and no default set.";
- return false;
- }
-
- QFile file(path);
-
- // Try to open the file and fail if we can't.
- // TODO: We should probably report this error to the user.
- if (!file.open(QIODevice::ReadOnly))
- {
- qCritical() << QString("Failed to read the account list file (%1).").arg(path).toUtf8();
- return false;
- }
-
- // Read the file and close it.
- QByteArray jsonData = file.readAll();
- file.close();
-
- QJsonParseError parseError;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
-
- // Fail if the JSON is invalid.
- if (parseError.error != QJsonParseError::NoError)
- {
- qCritical() << QString("Failed to parse account list file: %1 at offset %2")
- .arg(parseError.errorString(), QString::number(parseError.offset))
- .toUtf8();
- return false;
- }
-
- // Make sure the root is an object.
- if (!jsonDoc.isObject())
- {
- qCritical() << "Invalid account list JSON: Root should be an array.";
- return false;
- }
-
- QJsonObject root = jsonDoc.object();
-
- // Make sure the format version matches.
- if (root.value("formatVersion").toVariant().toInt() != ACCOUNT_LIST_FORMAT_VERSION)
- {
- QString newName = "accounts-old.json";
- qWarning() << "Format version mismatch when loading account list. Existing one will be renamed to"
- << newName;
-
- // Attempt to rename the old version.
- file.rename(newName);
- return false;
- }
-
- // Now, load the accounts array.
- beginResetModel();
- QJsonArray accounts = root.value("accounts").toArray();
- for (QJsonValue accountVal : accounts)
- {
- QJsonObject accountObj = accountVal.toObject();
- MojangAccountPtr account = MojangAccount::loadFromJson(accountObj);
- if (account.get() != nullptr)
- {
- connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
- m_accounts.append(account);
- }
- else
- {
- qWarning() << "Failed to load an account.";
- }
- }
- // Load the active account.
- m_activeAccount = findAccount(root.value("activeAccount").toString(""));
- endResetModel();
- return true;
-}
-
-bool MojangAccountList::saveList(const QString &filePath)
-{
- QString path(filePath);
- if (path.isEmpty())
- path = m_listFilePath;
- if (path.isEmpty())
- {
- qCritical() << "Can't save Mojang account list. No file path given and no default set.";
- return false;
- }
-
- // make sure the parent folder exists
- if(!FS::ensureFilePathExists(path))
- return false;
-
- // make sure the file wasn't overwritten with a folder before (fixes a bug)
- QFileInfo finfo(path);
- if(finfo.isDir())
- {
- QDir badDir(path);
- badDir.removeRecursively();
- }
-
- qDebug() << "Writing account list to" << path;
-
- qDebug() << "Building JSON data structure.";
- // Build the JSON document to write to the list file.
- QJsonObject root;
-
- root.insert("formatVersion", ACCOUNT_LIST_FORMAT_VERSION);
-
- // Build a list of accounts.
- qDebug() << "Building account array.";
- QJsonArray accounts;
- for (MojangAccountPtr account : m_accounts)
- {
- QJsonObject accountObj = account->saveToJson();
- accounts.append(accountObj);
- }
-
- // Insert the account list into the root object.
- root.insert("accounts", accounts);
-
- if(m_activeAccount)
- {
- // Save the active account.
- root.insert("activeAccount", m_activeAccount->username());
- }
-
- // Create a JSON document object to convert our JSON to bytes.
- QJsonDocument doc(root);
-
- // Now that we're done building the JSON object, we can write it to the file.
- qDebug() << "Writing account list to file.";
- QFile file(path);
-
- // Try to open the file and fail if we can't.
- // TODO: We should probably report this error to the user.
- if (!file.open(QIODevice::WriteOnly))
- {
- qCritical() << QString("Failed to read the account list file (%1).").arg(path).toUtf8();
- return false;
- }
-
- // Write the JSON to the file.
- file.write(doc.toJson());
- file.setPermissions(QFile::ReadOwner|QFile::WriteOwner|QFile::ReadUser|QFile::WriteUser);
- file.close();
-
- qDebug() << "Saved account list to" << path;
-
- return true;
-}
-
-void MojangAccountList::setListFilePath(QString path, bool autosave)
-{
- m_listFilePath = path;
- m_autosave = autosave;
-}
-
-bool MojangAccountList::anyAccountIsValid()
-{
- for(auto account:m_accounts)
- {
- if(account->accountStatus() != NotVerified)
- return true;
- }
- return false;
-}
diff --git a/logic/auth/MojangAccountList.h b/logic/auth/MojangAccountList.h
deleted file mode 100644
index 49b71fab..00000000
--- a/logic/auth/MojangAccountList.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/* Copyright 2013-2015 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 <QObject>
-#include <QVariant>
-#include <QAbstractListModel>
-#include <QSharedPointer>
-
-#include "auth/MojangAccount.h"
-
-#include "multimc_logic_export.h"
-
-/*!
- * \brief List of available Mojang accounts.
- * This should be loaded in the background by MultiMC on startup.
- *
- * This class also inherits from QAbstractListModel. Methods from that
- * class determine how this list shows up in a list view. Said methods
- * all have a default implementation, but they can be overridden by subclasses to
- * change the behavior of the list.
- */
-class MULTIMC_LOGIC_EXPORT MojangAccountList : public QAbstractListModel
-{
- Q_OBJECT
-public:
- enum ModelRoles
- {
- PointerRole = 0x34B1CB48
- };
-
- enum VListColumns
- {
- // TODO: Add icon column.
-
- // First column - Active?
- ActiveColumn = 0,
-
- // Second column - Name
- NameColumn,
- };
-
- explicit MojangAccountList(QObject *parent = 0);
-
- //! Gets the account at the given index.
- virtual const MojangAccountPtr at(int i) const;
-
- //! Returns the number of accounts in the list.
- virtual int count() const;
-
- //////// List Model Functions ////////
- virtual QVariant data(const QModelIndex &index, int role) const;
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
- virtual int rowCount(const QModelIndex &parent) const;
- virtual int columnCount(const QModelIndex &parent) const;
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
-
- /*!
- * Adds a the given Mojang account to the account list.
- */
- virtual void addAccount(const MojangAccountPtr account);
-
- /*!
- * Removes the mojang account with the given username from the account list.
- */
- virtual void removeAccount(const QString &username);
-
- /*!
- * Removes the account at the given QModelIndex.
- */
- virtual void removeAccount(QModelIndex index);
-
- /*!
- * \brief Finds an account by its username.
- * \param The username of the account to find.
- * \return A const pointer to the account with the given username. NULL if
- * one doesn't exist.
- */
- virtual MojangAccountPtr findAccount(const QString &username) const;
-
- /*!
- * Sets the default path to save the list file to.
- * If autosave is true, this list will automatically save to the given path whenever it changes.
- * THIS FUNCTION DOES NOT LOAD THE LIST. If you set autosave, be sure to call loadList() immediately
- * after calling this function to ensure an autosaved change doesn't overwrite the list you intended
- * to load.
- */
- virtual void setListFilePath(QString path, bool autosave = false);
-
- /*!
- * \brief Loads the account list from the given file path.
- * If the given file is an empty string (default), will load from the default account list file.
- * \return True if successful, otherwise false.
- */
- virtual bool loadList(const QString &file = "");
-
- /*!
- * \brief Saves the account list to the given file.
- * If the given file is an empty string (default), will save from the default account list file.
- * \return True if successful, otherwise false.
- */
- virtual bool saveList(const QString &file = "");
-
- /*!
- * \brief Gets a pointer to the account that the user has selected as their "active" account.
- * Which account is active can be overridden on a per-instance basis, but this will return the one that
- * is set as active globally.
- * \return The currently active MojangAccount. If there isn't an active account, returns a null pointer.
- */
- virtual MojangAccountPtr activeAccount() const;
-
- /*!
- * Sets the given account as the current active account.
- * If the username given is an empty string, sets the active account to nothing.
- */
- virtual void setActiveAccount(const QString &username);
-
- /*!
- * Returns true if any of the account is at least Validated
- */
- bool anyAccountIsValid();
-
-signals:
- /*!
- * Signal emitted to indicate that the account list has changed.
- * This will also fire if the value of an element in the list changes (will be implemented
- * later).
- */
- void listChanged();
-
- /*!
- * Signal emitted to indicate that the active account has changed.
- */
- void activeAccountChanged();
-
-public
-slots:
- /**
- * This is called when one of the accounts changes and the list needs to be updated
- */
- void accountChanged();
-
-protected:
- /*!
- * Called whenever the list changes.
- * This emits the listChanged() signal and autosaves the list (if autosave is enabled).
- */
- void onListChanged();
-
- /*!
- * Called whenever the active account changes.
- * Emits the activeAccountChanged() signal and autosaves the list if enabled.
- */
- void onActiveChanged();
-
- QList<MojangAccountPtr> m_accounts;
-
- /*!
- * Account that is currently active.
- */
- MojangAccountPtr m_activeAccount;
-
- //! Path to the account list file. Empty string if there isn't one.
- QString m_listFilePath;
-
- /*!
- * If true, the account list will automatically save to the account list path when it changes.
- * Ignored if m_listFilePath is blank.
- */
- bool m_autosave = false;
-
-protected
-slots:
- /*!
- * Updates this list with the given list of accounts.
- * This is done by copying each account in the given list and inserting it
- * into this one.
- * We need to do this so that we can set the parents of the accounts are set to this
- * account list. This can't be done in the load task, because the accounts the load
- * task creates are on the load task's thread and Qt won't allow their parents
- * to be set to something created on another thread.
- * To get around that problem, we invoke this method on the GUI thread, which
- * then copies the accounts and sets their parents correctly.
- * \param accounts List of accounts whose parents should be set.
- */
- virtual void updateListData(QList<MojangAccountPtr> versions);
-};
diff --git a/logic/auth/YggdrasilTask.cpp b/logic/auth/YggdrasilTask.cpp
deleted file mode 100644
index 929ab0bf..00000000
--- a/logic/auth/YggdrasilTask.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/* Copyright 2013-2015 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 <auth/YggdrasilTask.h>
-
-#include <QObject>
-#include <QString>
-#include <QJsonObject>
-#include <QJsonDocument>
-#include <QNetworkReply>
-#include <QByteArray>
-
-#include <Env.h>
-#include <auth/MojangAccount.h>
-#include <net/URLConstants.h>
-
-#include <QDebug>
-
-YggdrasilTask::YggdrasilTask(MojangAccount *account, QObject *parent)
- : Task(parent), m_account(account)
-{
- changeState(STATE_CREATED);
-}
-
-void YggdrasilTask::executeTask()
-{
- changeState(STATE_SENDING_REQUEST);
-
- // Get the content of the request we're going to send to the server.
- QJsonDocument doc(getRequestContent());
-
- auto worker = ENV.qnam();
- QUrl reqUrl("https://" + URLConstants::AUTH_BASE + getEndpoint());
- QNetworkRequest netRequest(reqUrl);
- netRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- QByteArray requestData = doc.toJson();
- m_netReply = worker->post(netRequest, requestData);
- connect(m_netReply, &QNetworkReply::finished, this, &YggdrasilTask::processReply);
- connect(m_netReply, &QNetworkReply::uploadProgress, this, &YggdrasilTask::refreshTimers);
- connect(m_netReply, &QNetworkReply::downloadProgress, this, &YggdrasilTask::refreshTimers);
- connect(m_netReply, &QNetworkReply::sslErrors, this, &YggdrasilTask::sslErrors);
- timeout_keeper.setSingleShot(true);
- timeout_keeper.start(timeout_max);
- counter.setSingleShot(false);
- counter.start(time_step);
- progress(0, timeout_max);
- connect(&timeout_keeper, &QTimer::timeout, this, &YggdrasilTask::abortByTimeout);
- connect(&counter, &QTimer::timeout, this, &YggdrasilTask::heartbeat);
-}
-
-void YggdrasilTask::refreshTimers(qint64, qint64)
-{
- timeout_keeper.stop();
- timeout_keeper.start(timeout_max);
- progress(count = 0, timeout_max);
-}
-void YggdrasilTask::heartbeat()
-{
- count += time_step;
- progress(count, timeout_max);
-}
-
-bool YggdrasilTask::abort()
-{
- progress(timeout_max, timeout_max);
- // TODO: actually use this in a meaningful way
- m_aborted = YggdrasilTask::BY_USER;
- m_netReply->abort();
- return true;
-}
-
-void YggdrasilTask::abortByTimeout()
-{
- progress(timeout_max, timeout_max);
- // TODO: actually use this in a meaningful way
- m_aborted = YggdrasilTask::BY_TIMEOUT;
- m_netReply->abort();
-}
-
-void YggdrasilTask::sslErrors(QList<QSslError> errors)
-{
- int i = 1;
- for (auto error : errors)
- {
- qCritical() << "LOGIN SSL Error #" << i << " : " << error.errorString();
- auto cert = error.certificate();
- qCritical() << "Certificate in question:\n" << cert.toText();
- i++;
- }
-}
-
-void YggdrasilTask::processReply()
-{
- changeState(STATE_PROCESSING_RESPONSE);
-
- switch (m_netReply->error())
- {
- case QNetworkReply::NoError:
- break;
- case QNetworkReply::TimeoutError:
- changeState(STATE_FAILED_SOFT, tr("Authentication operation timed out."));
- return;
- case QNetworkReply::OperationCanceledError:
- changeState(STATE_FAILED_SOFT, tr("Authentication operation cancelled."));
- return;
- case QNetworkReply::SslHandshakeFailedError:
- changeState(
- STATE_FAILED_SOFT,
- tr("<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>"
- "<ul>"
- "<li>You use Windows XP and need to <a "
- "href=\"http://www.microsoft.com/en-us/download/details.aspx?id=38918\">update "
- "your root certificates</a></li>"
- "<li>Some device on your network is interfering with SSL traffic. In that case, "
- "you have bigger worries than Minecraft not starting.</li>"
- "<li>Possibly something else. Check the MultiMC log file for details</li>"
- "</ul>"));
- return;
- // used for invalid credentials and similar errors. Fall through.
- case QNetworkReply::ContentOperationNotPermittedError:
- break;
- default:
- changeState(STATE_FAILED_SOFT,
- tr("Authentication operation failed due to a network error: %1 (%2)")
- .arg(m_netReply->errorString()).arg(m_netReply->error()));
- return;
- }
-
- // Try to parse the response regardless of the response code.
- // Sometimes the auth server will give more information and an error code.
- QJsonParseError jsonError;
- QByteArray replyData = m_netReply->readAll();
- QJsonDocument doc = QJsonDocument::fromJson(replyData, &jsonError);
- // Check the response code.
- int responseCode = m_netReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
-
- if (responseCode == 200)
- {
- // If the response code was 200, then there shouldn't be an error. Make sure
- // anyways.
- // Also, sometimes an empty reply indicates success. If there was no data received,
- // pass an empty json object to the processResponse function.
- if (jsonError.error == QJsonParseError::NoError || replyData.size() == 0)
- {
- processResponse(replyData.size() > 0 ? doc.object() : QJsonObject());
- return;
- }
- else
- {
- changeState(STATE_FAILED_SOFT, tr("Failed to parse authentication server response "
- "JSON response: %1 at offset %2.")
- .arg(jsonError.errorString())
- .arg(jsonError.offset));
- qCritical() << replyData;
- }
- return;
- }
-
- // If the response code was not 200, then Yggdrasil may have given us information
- // about the error.
- // If we can parse the response, then get information from it. Otherwise just say
- // there was an unknown error.
- if (jsonError.error == QJsonParseError::NoError)
- {
- // We were able to parse the server's response. Woo!
- // Call processError. If a subclass has overridden it then they'll handle their
- // stuff there.
- qDebug() << "The request failed, but the server gave us an error message. "
- "Processing error.";
- processError(doc.object());
- }
- else
- {
- // The server didn't say anything regarding the error. Give the user an unknown
- // error.
- qDebug()
- << "The request failed and the server gave no error message. Unknown error.";
- changeState(STATE_FAILED_SOFT,
- tr("An unknown error occurred when trying to communicate with the "
- "authentication server: %1").arg(m_netReply->errorString()));
- }
-}
-
-void YggdrasilTask::processError(QJsonObject responseData)
-{
- QJsonValue errorVal = responseData.value("error");
- QJsonValue errorMessageValue = responseData.value("errorMessage");
- QJsonValue causeVal = responseData.value("cause");
-
- if (errorVal.isString() && errorMessageValue.isString())
- {
- m_error = std::shared_ptr<Error>(new Error{
- errorVal.toString(""), errorMessageValue.toString(""), causeVal.toString("")});
- changeState(STATE_FAILED_HARD, m_error->m_errorMessageVerbose);
- }
- else
- {
- // Error is not in standard format. Don't set m_error and return unknown error.
- changeState(STATE_FAILED_HARD, tr("An unknown Yggdrasil error occurred."));
- }
-}
-
-QString YggdrasilTask::getStateMessage() const
-{
- switch (m_state)
- {
- case STATE_CREATED:
- return "Waiting...";
- case STATE_SENDING_REQUEST:
- return tr("Sending request to auth servers...");
- case STATE_PROCESSING_RESPONSE:
- return tr("Processing response from servers...");
- case STATE_SUCCEEDED:
- return tr("Authentication task succeeded.");
- case STATE_FAILED_SOFT:
- return tr("Failed to contact the authentication server.");
- case STATE_FAILED_HARD:
- return tr("Failed to authenticate.");
- default:
- return tr("...");
- }
-}
-
-void YggdrasilTask::changeState(YggdrasilTask::State newState, QString reason)
-{
- m_state = newState;
- setStatus(getStateMessage());
- if (newState == STATE_SUCCEEDED)
- {
- emitSucceeded();
- }
- else if (newState == STATE_FAILED_HARD || newState == STATE_FAILED_SOFT)
- {
- emitFailed(reason);
- }
-}
-
-YggdrasilTask::State YggdrasilTask::state()
-{
- return m_state;
-}
diff --git a/logic/auth/YggdrasilTask.h b/logic/auth/YggdrasilTask.h
deleted file mode 100644
index d989bee3..00000000
--- a/logic/auth/YggdrasilTask.h
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Copyright 2013-2015 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 <tasks/Task.h>
-
-#include <QString>
-#include <QJsonObject>
-#include <QTimer>
-#include <qsslerror.h>
-
-#include "auth/MojangAccount.h"
-
-class QNetworkReply;
-
-/**
- * A Yggdrasil task is a task that performs an operation on a given mojang account.
- */
-class YggdrasilTask : public Task
-{
- Q_OBJECT
-public:
- explicit YggdrasilTask(MojangAccount * account, QObject *parent = 0);
-
- /**
- * assign a session to this task. the session will be filled with required infomration
- * upon completion
- */
- void assignSession(AuthSessionPtr session)
- {
- m_session = session;
- }
-
- /// get the assigned session for filling with information.
- AuthSessionPtr getAssignedSession()
- {
- return m_session;
- }
-
- /**
- * Class describing a Yggdrasil error response.
- */
- struct Error
- {
- QString m_errorMessageShort;
- QString m_errorMessageVerbose;
- QString m_cause;
- };
-
- enum AbortedBy
- {
- BY_NOTHING,
- BY_USER,
- BY_TIMEOUT
- } m_aborted = BY_NOTHING;
-
- /**
- * Enum for describing the state of the current task.
- * Used by the getStateMessage function to determine what the status message should be.
- */
- enum State
- {
- STATE_CREATED,
- STATE_SENDING_REQUEST,
- STATE_PROCESSING_RESPONSE,
- STATE_FAILED_SOFT, //!< soft failure. this generally means the user auth details haven't been invalidated
- STATE_FAILED_HARD, //!< hard failure. auth is invalid
- STATE_SUCCEEDED
- } m_state = STATE_CREATED;
-
-protected:
-
- virtual void executeTask() override;
-
- /**
- * Gets the JSON object that will be sent to the authentication server.
- * Should be overridden by subclasses.
- */
- virtual QJsonObject getRequestContent() const = 0;
-
- /**
- * Gets the endpoint to POST to.
- * No leading slash.
- */
- virtual QString getEndpoint() const = 0;
-
- /**
- * Processes the response received from the server.
- * If an error occurred, this should emit a failed signal and return false.
- * If Yggdrasil gave an error response, it should call setError() first, and then return false.
- * Otherwise, it should return true.
- * Note: If the response from the server was blank, and the HTTP code was 200, this function is called with
- * an empty QJsonObject.
- */
- virtual void processResponse(QJsonObject responseData) = 0;
-
- /**
- * Processes an error response received from the server.
- * The default implementation will read data from Yggdrasil's standard error response format and set it as this task's Error.
- * \returns a QString error message that will be passed to emitFailed.
- */
- virtual void processError(QJsonObject responseData);
-
- /**
- * Returns the state message for the given state.
- * Used to set the status message for the task.
- * Should be overridden by subclasses that want to change messages for a given state.
- */
- virtual QString getStateMessage() const;
-
-protected
-slots:
- void processReply();
- void refreshTimers(qint64, qint64);
- void heartbeat();
- void sslErrors(QList<QSslError>);
-
- void changeState(State newState, QString reason=QString());
-public
-slots:
- virtual bool abort() override;
- void abortByTimeout();
- State state();
-protected:
- // FIXME: segfault disaster waiting to happen
- MojangAccount *m_account = nullptr;
- QNetworkReply *m_netReply = nullptr;
- std::shared_ptr<Error> m_error;
- QTimer timeout_keeper;
- QTimer counter;
- int count = 0; // num msec since time reset
-
- const int timeout_max = 30000;
- const int time_step = 50;
-
- AuthSessionPtr m_session;
-};
diff --git a/logic/auth/flows/AuthenticateTask.cpp b/logic/auth/flows/AuthenticateTask.cpp
deleted file mode 100644
index a609d28b..00000000
--- a/logic/auth/flows/AuthenticateTask.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-
-/* Copyright 2013-2015 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 <auth/flows/AuthenticateTask.h>
-
-#include <auth/MojangAccount.h>
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QVariant>
-
-#include <QDebug>
-#include <QUuid>
-
-AuthenticateTask::AuthenticateTask(MojangAccount * account, const QString &password,
- QObject *parent)
- : YggdrasilTask(account, parent), m_password(password)
-{
-}
-
-QJsonObject AuthenticateTask::getRequestContent() const
-{
- /*
- * {
- * "agent": { // optional
- * "name": "Minecraft", // So far this is the only encountered value
- * "version": 1 // This number might be increased
- * // by the vanilla client in the future
- * },
- * "username": "mojang account name", // Can be an email address or player name for
- // unmigrated accounts
- * "password": "mojang account password",
- * "clientToken": "client identifier" // optional
- * "requestUser": true/false // request the user structure
- * }
- */
- QJsonObject req;
-
- {
- QJsonObject agent;
- // C++ makes string literals void* for some stupid reason, so we have to tell it
- // QString... Thanks Obama.
- agent.insert("name", QString("Minecraft"));
- agent.insert("version", 1);
- req.insert("agent", agent);
- }
-
- req.insert("username", m_account->username());
- req.insert("password", m_password);
- req.insert("requestUser", true);
-
- // If we already have a client token, give it to the server.
- // Otherwise, let the server give us one.
-
- if(m_account->m_clientToken.isEmpty())
- {
- auto uuid = QUuid::createUuid();
- auto uuidString = uuid.toString().remove('{').remove('-').remove('}');
- m_account->m_clientToken = uuidString;
- }
- req.insert("clientToken", m_account->m_clientToken);
-
- return req;
-}
-
-void AuthenticateTask::processResponse(QJsonObject responseData)
-{
- // Read the response data. We need to get the client token, access token, and the selected
- // profile.
- qDebug() << "Processing authentication response.";
- // qDebug() << responseData;
- // If we already have a client token, make sure the one the server gave us matches our
- // existing one.
- qDebug() << "Getting client token.";
- QString clientToken = responseData.value("clientToken").toString("");
- if (clientToken.isEmpty())
- {
- // Fail if the server gave us an empty client token
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token."));
- return;
- }
- if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken)
- {
- changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported."));
- return;
- }
- // Set the client token.
- m_account->m_clientToken = clientToken;
-
- // Now, we set the access token.
- qDebug() << "Getting access token.";
- QString accessToken = responseData.value("accessToken").toString("");
- if (accessToken.isEmpty())
- {
- // Fail if the server didn't give us an access token.
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token."));
- return;
- }
- // Set the access token.
- m_account->m_accessToken = accessToken;
-
- // Now we load the list of available profiles.
- // Mojang hasn't yet implemented the profile system,
- // but we might as well support what's there so we
- // don't have trouble implementing it later.
- qDebug() << "Loading profile list.";
- QJsonArray availableProfiles = responseData.value("availableProfiles").toArray();
- QList<AccountProfile> loadedProfiles;
- for (auto iter : availableProfiles)
- {
- QJsonObject profile = iter.toObject();
- // Profiles are easy, we just need their ID and name.
- QString id = profile.value("id").toString("");
- QString name = profile.value("name").toString("");
- bool legacy = profile.value("legacy").toBool(false);
-
- if (id.isEmpty() || name.isEmpty())
- {
- // This should never happen, but we might as well
- // warn about it if it does so we can debug it easily.
- // You never know when Mojang might do something truly derpy.
- qWarning() << "Found entry in available profiles list with missing ID or name "
- "field. Ignoring it.";
- }
-
- // Now, add a new AccountProfile entry to the list.
- loadedProfiles.append({id, name, legacy});
- }
- // Put the list of profiles we loaded into the MojangAccount object.
- m_account->m_profiles = loadedProfiles;
-
- // Finally, we set the current profile to the correct value. This is pretty simple.
- // We do need to make sure that the current profile that the server gave us
- // is actually in the available profiles list.
- // If it isn't, we'll just fail horribly (*shouldn't* ever happen, but you never know).
- qDebug() << "Setting current profile.";
- QJsonObject currentProfile = responseData.value("selectedProfile").toObject();
- QString currentProfileId = currentProfile.value("id").toString("");
- if (currentProfileId.isEmpty())
- {
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify a currently selected profile. The account exists, but likely isn't premium."));
- return;
- }
- if (!m_account->setCurrentProfile(currentProfileId))
- {
- changeState(STATE_FAILED_HARD, tr("Authentication server specified a selected profile that wasn't in the available profiles list."));
- return;
- }
-
- // this is what the vanilla launcher passes to the userProperties launch param
- if (responseData.contains("user"))
- {
- User u;
- auto obj = responseData.value("user").toObject();
- u.id = obj.value("id").toString();
- auto propArray = obj.value("properties").toArray();
- for (auto prop : propArray)
- {
- auto propTuple = prop.toObject();
- auto name = propTuple.value("name").toString();
- auto value = propTuple.value("value").toString();
- u.properties.insert(name, value);
- }
- m_account->m_user = u;
- }
-
- // We've made it through the minefield of possible errors. Return true to indicate that
- // we've succeeded.
- qDebug() << "Finished reading authentication response.";
- changeState(STATE_SUCCEEDED);
-}
-
-QString AuthenticateTask::getEndpoint() const
-{
- return "authenticate";
-}
-
-QString AuthenticateTask::getStateMessage() const
-{
- switch (m_state)
- {
- case STATE_SENDING_REQUEST:
- return tr("Authenticating: Sending request...");
- case STATE_PROCESSING_RESPONSE:
- return tr("Authenticating: Processing response...");
- default:
- return YggdrasilTask::getStateMessage();
- }
-}
diff --git a/logic/auth/flows/AuthenticateTask.h b/logic/auth/flows/AuthenticateTask.h
deleted file mode 100644
index 65975ae5..00000000
--- a/logic/auth/flows/AuthenticateTask.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* Copyright 2013-2015 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 <auth/YggdrasilTask.h>
-
-#include <QObject>
-#include <QString>
-#include <QJsonObject>
-
-/**
- * The authenticate task takes a MojangAccount with no access token and password and attempts to
- * authenticate with Mojang's servers.
- * If successful, it will set the MojangAccount's access token.
- */
-class AuthenticateTask : public YggdrasilTask
-{
- Q_OBJECT
-public:
- AuthenticateTask(MojangAccount *account, const QString &password, QObject *parent = 0);
-
-protected:
- virtual QJsonObject getRequestContent() const override;
-
- virtual QString getEndpoint() const override;
-
- virtual void processResponse(QJsonObject responseData) override;
-
- virtual QString getStateMessage() const override;
-
-private:
- QString m_password;
-};
diff --git a/logic/auth/flows/RefreshTask.cpp b/logic/auth/flows/RefreshTask.cpp
deleted file mode 100644
index 83511200..00000000
--- a/logic/auth/flows/RefreshTask.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/* Copyright 2013-2015 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 <auth/flows/RefreshTask.h>
-
-#include <auth/MojangAccount.h>
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QVariant>
-
-#include <QDebug>
-
-RefreshTask::RefreshTask(MojangAccount *account) : YggdrasilTask(account)
-{
-}
-
-QJsonObject RefreshTask::getRequestContent() const
-{
- /*
- * {
- * "clientToken": "client identifier"
- * "accessToken": "current access token to be refreshed"
- * "selectedProfile": // specifying this causes errors
- * {
- * "id": "profile ID"
- * "name": "profile name"
- * }
- * "requestUser": true/false // request the user structure
- * }
- */
- QJsonObject req;
- req.insert("clientToken", m_account->m_clientToken);
- req.insert("accessToken", m_account->m_accessToken);
- /*
- {
- auto currentProfile = m_account->currentProfile();
- QJsonObject profile;
- profile.insert("id", currentProfile->id());
- profile.insert("name", currentProfile->name());
- req.insert("selectedProfile", profile);
- }
- */
- req.insert("requestUser", true);
-
- return req;
-}
-
-void RefreshTask::processResponse(QJsonObject responseData)
-{
- // Read the response data. We need to get the client token, access token, and the selected
- // profile.
- qDebug() << "Processing authentication response.";
-
- // qDebug() << responseData;
- // If we already have a client token, make sure the one the server gave us matches our
- // existing one.
- QString clientToken = responseData.value("clientToken").toString("");
- if (clientToken.isEmpty())
- {
- // Fail if the server gave us an empty client token
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send a client token."));
- return;
- }
- if (!m_account->m_clientToken.isEmpty() && clientToken != m_account->m_clientToken)
- {
- changeState(STATE_FAILED_HARD, tr("Authentication server attempted to change the client token. This isn't supported."));
- return;
- }
-
- // Now, we set the access token.
- qDebug() << "Getting new access token.";
- QString accessToken = responseData.value("accessToken").toString("");
- if (accessToken.isEmpty())
- {
- // Fail if the server didn't give us an access token.
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't send an access token."));
- return;
- }
-
- // we validate that the server responded right. (our current profile = returned current
- // profile)
- QJsonObject currentProfile = responseData.value("selectedProfile").toObject();
- QString currentProfileId = currentProfile.value("id").toString("");
- if (m_account->currentProfile()->id != currentProfileId)
- {
- changeState(STATE_FAILED_HARD, tr("Authentication server didn't specify the same prefile as expected."));
- return;
- }
-
- // this is what the vanilla launcher passes to the userProperties launch param
- if (responseData.contains("user"))
- {
- User u;
- auto obj = responseData.value("user").toObject();
- u.id = obj.value("id").toString();
- auto propArray = obj.value("properties").toArray();
- for (auto prop : propArray)
- {
- auto propTuple = prop.toObject();
- auto name = propTuple.value("name").toString();
- auto value = propTuple.value("value").toString();
- u.properties.insert(name, value);
- }
- m_account->m_user = u;
- }
-
- // We've made it through the minefield of possible errors. Return true to indicate that
- // we've succeeded.
- qDebug() << "Finished reading refresh response.";
- // Reset the access token.
- m_account->m_accessToken = accessToken;
- changeState(STATE_SUCCEEDED);
-}
-
-QString RefreshTask::getEndpoint() const
-{
- return "refresh";
-}
-
-QString RefreshTask::getStateMessage() const
-{
- switch (m_state)
- {
- case STATE_SENDING_REQUEST:
- return tr("Refreshing login token...");
- case STATE_PROCESSING_RESPONSE:
- return tr("Refreshing login token: Processing response...");
- default:
- return YggdrasilTask::getStateMessage();
- }
-}
diff --git a/logic/auth/flows/RefreshTask.h b/logic/auth/flows/RefreshTask.h
deleted file mode 100644
index 6894e963..00000000
--- a/logic/auth/flows/RefreshTask.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright 2013-2015 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 <auth/YggdrasilTask.h>
-
-#include <QObject>
-#include <QString>
-#include <QJsonObject>
-
-/**
- * The authenticate task takes a MojangAccount with a possibly timed-out access token
- * and attempts to authenticate with Mojang's servers.
- * If successful, it will set the new access token. The token is considered validated.
- */
-class RefreshTask : public YggdrasilTask
-{
- Q_OBJECT
-public:
- RefreshTask(MojangAccount * account);
-
-protected:
- virtual QJsonObject getRequestContent() const override;
-
- virtual QString getEndpoint() const override;
-
- virtual void processResponse(QJsonObject responseData) override;
-
- virtual QString getStateMessage() const override;
-};
-
diff --git a/logic/auth/flows/ValidateTask.cpp b/logic/auth/flows/ValidateTask.cpp
deleted file mode 100644
index 9a4dcd6d..00000000
--- a/logic/auth/flows/ValidateTask.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-
-/* Copyright 2013-2015 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 <auth/flows/ValidateTask.h>
-
-#include <auth/MojangAccount.h>
-
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QVariant>
-
-#include <QDebug>
-
-ValidateTask::ValidateTask(MojangAccount * account, QObject *parent)
- : YggdrasilTask(account, parent)
-{
-}
-
-QJsonObject ValidateTask::getRequestContent() const
-{
- QJsonObject req;
- req.insert("accessToken", m_account->m_accessToken);
- return req;
-}
-
-void ValidateTask::processResponse(QJsonObject responseData)
-{
- // Assume that if processError wasn't called, then the request was successful.
- changeState(YggdrasilTask::STATE_SUCCEEDED);
-}
-
-QString ValidateTask::getEndpoint() const
-{
- return "validate";
-}
-
-QString ValidateTask::getStateMessage() const
-{
- switch (m_state)
- {
- case YggdrasilTask::STATE_SENDING_REQUEST:
- return tr("Validating access token: Sending request...");
- case YggdrasilTask::STATE_PROCESSING_RESPONSE:
- return tr("Validating access token: Processing response...");
- default:
- return YggdrasilTask::getStateMessage();
- }
-}
diff --git a/logic/auth/flows/ValidateTask.h b/logic/auth/flows/ValidateTask.h
deleted file mode 100644
index 204596f9..00000000
--- a/logic/auth/flows/ValidateTask.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright 2013-2015 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.
- */
-
-/*
- * :FIXME: DEAD CODE, DEAD CODE, DEAD CODE! :FIXME:
- */
-
-#pragma once
-
-#include <auth/YggdrasilTask.h>
-
-#include <QObject>
-#include <QString>
-#include <QJsonObject>
-
-/**
- * The validate task takes a MojangAccount and checks to make sure its access token is valid.
- */
-class ValidateTask : public YggdrasilTask
-{
- Q_OBJECT
-public:
- ValidateTask(MojangAccount *account, QObject *parent = 0);
-
-protected:
- virtual QJsonObject getRequestContent() const override;
-
- virtual QString getEndpoint() const override;
-
- virtual void processResponse(QJsonObject responseData) override;
-
- virtual QString getStateMessage() const override;
-
-private:
-};