aboutsummaryrefslogtreecommitdiff
path: root/api/logic/minecraft/auth
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2021-07-25 19:11:59 +0200
committerPetr Mrázek <peterix@gmail.com>2021-07-25 19:50:44 +0200
commit20b9f2b42a3b58b6081af271774fbcc34025dccb (patch)
tree064fa59facb3357139b47bd4e60bfc8edb35ca11 /api/logic/minecraft/auth
parentdd133680858351e3e07690e286882327a4f42ba5 (diff)
downloadPrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.tar.gz
PrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.tar.bz2
PrismLauncher-20b9f2b42a3b58b6081af271774fbcc34025dccb.zip
NOISSUE Flatten gui and logic libraries into MultiMC
Diffstat (limited to 'api/logic/minecraft/auth')
-rw-r--r--api/logic/minecraft/auth/AuthSession.cpp30
-rw-r--r--api/logic/minecraft/auth/AuthSession.h54
-rw-r--r--api/logic/minecraft/auth/MojangAccount.cpp315
-rw-r--r--api/logic/minecraft/auth/MojangAccount.h182
-rw-r--r--api/logic/minecraft/auth/MojangAccountList.cpp468
-rw-r--r--api/logic/minecraft/auth/MojangAccountList.h201
-rw-r--r--api/logic/minecraft/auth/YggdrasilTask.cpp255
-rw-r--r--api/logic/minecraft/auth/YggdrasilTask.h151
-rw-r--r--api/logic/minecraft/auth/flows/AuthenticateTask.cpp202
-rw-r--r--api/logic/minecraft/auth/flows/AuthenticateTask.h46
-rw-r--r--api/logic/minecraft/auth/flows/RefreshTask.cpp144
-rw-r--r--api/logic/minecraft/auth/flows/RefreshTask.h44
-rw-r--r--api/logic/minecraft/auth/flows/ValidateTask.cpp61
-rw-r--r--api/logic/minecraft/auth/flows/ValidateTask.h47
14 files changed, 0 insertions, 2200 deletions
diff --git a/api/logic/minecraft/auth/AuthSession.cpp b/api/logic/minecraft/auth/AuthSession.cpp
deleted file mode 100644
index 4e858796..00000000
--- a/api/logic/minecraft/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/api/logic/minecraft/auth/AuthSession.h b/api/logic/minecraft/auth/AuthSession.h
deleted file mode 100644
index b397d9a1..00000000
--- a/api/logic/minecraft/auth/AuthSession.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#pragma once
-
-#include <QString>
-#include <QMultiMap>
-#include <memory>
-
-#include "multimc_logic_export.h"
-
-class MojangAccount;
-
-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;
- std::shared_ptr<MojangAccount> m_accountPtr;
-};
-
-typedef std::shared_ptr<AuthSession> AuthSessionPtr;
diff --git a/api/logic/minecraft/auth/MojangAccount.cpp b/api/logic/minecraft/auth/MojangAccount.cpp
deleted file mode 100644
index f5853fe3..00000000
--- a/api/logic/minecraft/auth/MojangAccount.cpp
+++ /dev/null
@@ -1,315 +0,0 @@
-/* Copyright 2013-2021 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(accountStatus() == Verified && !session->wants_online)
- {
- session->status = AuthSession::PlayableOffline;
- session->auth_server_online = false;
- fillSession(session);
- return nullptr;
- }
- else
- {
- 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();
- session->m_accountPtr = shared_from_this();
-}
-
-void MojangAccount::decrementUses()
-{
- Usable::decrementUses();
- if(!isInUse())
- {
- emit changed();
- qWarning() << "Account" << m_username << "is no longer in use.";
- }
-}
-
-void MojangAccount::incrementUses()
-{
- bool wasInUse = isInUse();
- Usable::incrementUses();
- if(!wasInUse)
- {
- emit changed();
- qWarning() << "Account" << m_username << "is now in use.";
- }
-}
-
-void MojangAccount::invalidateClientToken()
-{
- m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
- emit changed();
-}
diff --git a/api/logic/minecraft/auth/MojangAccount.h b/api/logic/minecraft/auth/MojangAccount.h
deleted file mode 100644
index 30a5f2ff..00000000
--- a/api/logic/minecraft/auth/MojangAccount.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/* Copyright 2013-2021 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 "Usable.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,
- public Usable,
- public std::enable_shared_from_this<MojangAccount>
-{
- 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());
- void invalidateClientToken();
-
-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;
-
-protected: /* methods */
-
- void incrementUses() override;
- void decrementUses() override;
-
-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/api/logic/minecraft/auth/MojangAccountList.cpp b/api/logic/minecraft/auth/MojangAccountList.cpp
deleted file mode 100644
index e584cb3b..00000000
--- a/api/logic/minecraft/auth/MojangAccountList.cpp
+++ /dev/null
@@ -1,468 +0,0 @@
-/* Copyright 2013-2021 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 "MojangAccountList.h"
-#include "MojangAccount.h"
-
-#include <QIODevice>
-#include <QFile>
-#include <QTextStream>
-#include <QJsonDocument>
-#include <QJsonArray>
-#include <QJsonObject>
-#include <QJsonParseError>
-#include <QDir>
-
-#include <QDebug>
-
-#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)
-{
- int row = m_accounts.count();
- beginInsertRows(QModelIndex(), row, row);
- connect(account.get(), SIGNAL(changed()), SLOT(accountChanged()));
- m_accounts.append(account);
- endInsertRows();
- onListChanged();
-}
-
-void MojangAccountList::removeAccount(const QString &username)
-{
- int idx = 0;
- for (auto account : m_accounts)
- {
- if (account->username() == username)
- {
- beginRemoveRows(QModelIndex(), idx, idx);
- m_accounts.removeOne(account);
- endRemoveRows();
- return;
- }
- idx++;
- }
- onListChanged();
-}
-
-void MojangAccountList::removeAccount(QModelIndex index)
-{
- int row = index.row();
- if(index.isValid() && row >= 0 && row < m_accounts.size())
- {
- auto & account = m_accounts[row];
- if(account == m_activeAccount)
- {
- m_activeAccount = nullptr;
- onActiveChanged();
- }
- beginRemoveRows(QModelIndex(), row, row);
- m_accounts.removeAt(index.row());
- endRemoveRows();
- onListChanged();
- }
-}
-
-MojangAccountPtr MojangAccountList::activeAccount() const
-{
- return m_activeAccount;
-}
-
-void MojangAccountList::setActiveAccount(const QString &username)
-{
- if (username.isEmpty() && m_activeAccount)
- {
- int idx = 0;
- auto prevActiveAcc = m_activeAccount;
- m_activeAccount = nullptr;
- for (MojangAccountPtr account : m_accounts)
- {
- if (account == prevActiveAcc)
- {
- emit dataChanged(index(idx), index(idx));
- }
- idx ++;
- }
- onActiveChanged();
- }
- else
- {
- auto currentActiveAccount = m_activeAccount;
- int currentActiveAccountIdx = -1;
- auto newActiveAccount = m_activeAccount;
- int newActiveAccountIdx = -1;
- int idx = 0;
- for (MojangAccountPtr account : m_accounts)
- {
- if (account->username() == username)
- {
- newActiveAccount = account;
- newActiveAccountIdx = idx;
- }
- if(currentActiveAccount == account)
- {
- currentActiveAccountIdx = idx;
- }
- idx++;
- }
- if(currentActiveAccount != newActiveAccount)
- {
- emit dataChanged(index(currentActiveAccountIdx), index(currentActiveAccountIdx));
- emit dataChanged(index(newActiveAccountIdx), index(newActiveAccountIdx));
- m_activeAccount = newActiveAccount;
- 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 ? Qt::Checked : Qt::Unchecked;
- }
-
- 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 &) const
-{
- // Return count
- return count();
-}
-
-int MojangAccountList::columnCount(const QModelIndex &) 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