Merge pull request #28 from AfoninZ/feature-accounts

Feature accounts
This commit is contained in:
Zakhar Afonin
2021-05-31 20:43:39 +03:00
committed by GitHub
7 changed files with 153 additions and 105 deletions

View File

@@ -29,17 +29,3 @@ bool AuthSession::MakeOffline(QString offline_playername)
status = PlayableOffline; status = PlayableOffline;
return true; return true;
} }
bool AuthSession::MakeCracked(QString offline_playername)
{
session = "-";
// Filling session with dummy data
client_token = "ff64ff64ff64ff64ff64ff64ff64ff64";
access_token = "ff64ff64ff64ff64ff64ff64ff64ff64";
// TODO: Fetch actual UUID's from Mojang API so they match with real ones
uuid = QString(QCryptographicHash::hash(offline_playername.toLocal8Bit(), QCryptographicHash::Md5).toHex());
player_name = offline_playername;
status = PlayableOffline;
return true;
}

View File

@@ -17,7 +17,6 @@ struct User
struct MULTIMC_LOGIC_EXPORT AuthSession struct MULTIMC_LOGIC_EXPORT AuthSession
{ {
bool MakeOffline(QString offline_playername); bool MakeOffline(QString offline_playername);
bool MakeCracked(QString offline_playername);
QString serializeUserProperties(); QString serializeUserProperties();

View File

@@ -38,6 +38,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
return nullptr; return nullptr;
} }
QString loginType = object.value("loginType").toString("mojang");
QString username = object.value("username").toString(""); QString username = object.value("username").toString("");
QString clientToken = object.value("clientToken").toString(""); QString clientToken = object.value("clientToken").toString("");
QString accessToken = object.value("accessToken").toString(""); QString accessToken = object.value("accessToken").toString("");
@@ -82,6 +83,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
*/ */
account->m_user = u; account->m_user = u;
} }
account->m_loginType = loginType;
account->m_username = username; account->m_username = username;
account->m_clientToken = clientToken; account->m_clientToken = clientToken;
account->m_accessToken = accessToken; account->m_accessToken = accessToken;
@@ -106,6 +108,7 @@ MojangAccountPtr MojangAccount::createFromUsername(const QString &username)
QJsonObject MojangAccount::saveToJson() const QJsonObject MojangAccount::saveToJson() const
{ {
QJsonObject json; QJsonObject json;
json.insert("loginType", m_loginType);
json.insert("username", m_username); json.insert("username", m_username);
json.insert("clientToken", m_clientToken); json.insert("clientToken", m_clientToken);
json.insert("accessToken", m_accessToken); json.insert("accessToken", m_accessToken);
@@ -142,6 +145,17 @@ QJsonObject MojangAccount::saveToJson() const
return json; return json;
} }
bool MojangAccount::setLoginType(const QString &loginType)
{
// TODO: Implement a cleaner validity check
if (loginType == "mojang" or loginType == "dummy")
{
m_loginType = loginType;
return true;
}
return false;
}
bool MojangAccount::setCurrentProfile(const QString &profileId) bool MojangAccount::setCurrentProfile(const QString &profileId)
{ {
for (int i = 0; i < m_profiles.length(); i++) for (int i = 0; i < m_profiles.length(); i++)
@@ -174,6 +188,27 @@ std::shared_ptr<YggdrasilTask> MojangAccount::login(AuthSessionPtr session, QStr
{ {
Q_ASSERT(m_currentTask.get() == nullptr); Q_ASSERT(m_currentTask.get() == nullptr);
// Handling alternative account types
if (m_loginType == "dummy")
{
if (session)
{
session->status = AuthSession::PlayableOnline;
session->auth_server_online = false;
fillSession(session);
}
if (!currentProfile())
{
// TODO: Proper profile support (idk how)
auto dummyProfile = AccountProfile();
dummyProfile.name = m_username;
dummyProfile.id = "-";
m_profiles.append(dummyProfile);
m_currentProfile = 0;
}
return nullptr;
}
// take care of the true offline status // take care of the true offline status
if (accountStatus() == NotVerified && password.isEmpty()) if (accountStatus() == NotVerified && password.isEmpty())
{ {
@@ -280,7 +315,7 @@ void MojangAccount::fillSession(AuthSessionPtr session)
} }
else else
{ {
session->player_name = "Player"; session->player_name = m_username;
session->session = "-"; session->session = "-";
} }
session->u = user(); session->u = user();

View File

@@ -85,6 +85,12 @@ public: /* construction */
public: /* manipulation */ public: /* manipulation */
/** /**
* Overrides the login type on the account.
* Accepts "mojang" and "dummy". Returns false if other.
*/
bool setLoginType(const QString &loginType);
/**
* Sets the currently selected profile to the profile with the given ID string. * 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 * If profileId is not in the list of available profiles, the function will simply return
* false. * false.
@@ -99,6 +105,11 @@ public: /* manipulation */
void invalidateClientToken(); void invalidateClientToken();
public: /* queries */ public: /* queries */
const QString &loginType() const
{
return m_loginType;
}
const QString &username() const const QString &username() const
{ {
return m_username; return m_username;
@@ -139,6 +150,11 @@ signals:
// TODO: better signalling for the various possible state changes - especially errors // TODO: better signalling for the various possible state changes - especially errors
protected: /* variables */ protected: /* variables */
// Authentication system used.
// Usable values: "mojang", "dummy"
QString m_loginType;
// Username taken by account.
QString m_username; QString m_username;
// Used to identify the client - the user can have multiple clients for the same account // Used to identify the client - the user can have multiple clients for the same account

View File

@@ -36,27 +36,6 @@ void LaunchController::login()
{ {
JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget); JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
// Mojang account login bypass
bool ok = false;
QString usedname = "Player";
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal, "Player", &ok);
if (!ok)
{
return;
}
if (name.length())
{
usedname = name;
}
m_session = std::make_shared<AuthSession>();
m_session->MakeCracked(usedname);
launchInstance();
// Original login code
/*
// Find an account to use. // Find an account to use.
std::shared_ptr<MojangAccountList> accounts = MMC->accounts(); std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
MojangAccountPtr account = accounts->activeAccount(); MojangAccountPtr account = accounts->activeAccount();
@@ -64,11 +43,11 @@ void LaunchController::login()
{ {
// Tell the user they need to log in at least one account in order to play. // Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox::selectable( auto reply = CustomMessageBox::selectable(
m_parentWidget, tr("No Accounts"), m_parentWidget, tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft " tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
"account logged in to MultiMC." "account logged in to MultiMC."
"Would you like to open the account manager to add an account now?"), "Would you like to open the account manager to add an account now?"),
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec(); QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
if (reply == QMessageBox::Yes) if (reply == QMessageBox::Yes)
{ {
@@ -135,75 +114,75 @@ void LaunchController::login()
} }
switch (m_session->status) switch (m_session->status)
{ {
case AuthSession::Undetermined: case AuthSession::Undetermined:
{
qCritical() << "Received undetermined session status during login. Bye.";
tryagain = false;
emitFailed(tr("Received undetermined session status during login."));
break;
}
case AuthSession::RequiresPassword:
{
EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
auto username = m_session->username;
auto chopN = [](QString toChop, int N) -> QString
{
if(toChop.size() > N)
{
auto left = toChop.left(N);
left += QString("\u25CF").repeated(toChop.size() - N);
return left;
}
return toChop;
};
if(username.contains('@'))
{
auto parts = username.split('@');
auto mailbox = chopN(parts[0],3);
QString domain = chopN(parts[1], 3);
username = mailbox + '@' + domain;
}
passDialog.setUsername(username);
if (passDialog.exec() == QDialog::Accepted)
{
password = passDialog.password();
}
else
{
tryagain = false;
}
break;
}
case AuthSession::PlayableOffline:
{
// we ask the user for a player name
bool ok = false;
QString usedname = m_session->player_name;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal, m_session->player_name, &ok);
if (!ok)
{ {
qCritical() << "Received undetermined session status during login. Bye.";
tryagain = false; tryagain = false;
emitFailed(tr("Received undetermined session status during login."));
break; break;
} }
if (name.length()) case AuthSession::RequiresPassword:
{ {
usedname = name; EditAccountDialog passDialog(failReason, m_parentWidget, EditAccountDialog::PasswordField);
auto username = m_session->username;
auto chopN = [](QString toChop, int N) -> QString
{
if(toChop.size() > N)
{
auto left = toChop.left(N);
left += QString("\u25CF").repeated(toChop.size() - N);
return left;
}
return toChop;
};
if(username.contains('@'))
{
auto parts = username.split('@');
auto mailbox = chopN(parts[0],3);
QString domain = chopN(parts[1], 3);
username = mailbox + '@' + domain;
}
passDialog.setUsername(username);
if (passDialog.exec() == QDialog::Accepted)
{
password = passDialog.password();
}
else
{
tryagain = false;
}
break;
}
case AuthSession::PlayableOffline:
{
// we ask the user for a player name
bool ok = false;
QString usedname = m_session->player_name;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"),
tr("Choose your offline mode player name."),
QLineEdit::Normal, m_session->player_name, &ok);
if (!ok)
{
tryagain = false;
break;
}
if (name.length())
{
usedname = name;
}
m_session->MakeOffline(usedname);
// offline flavored game from here :3
}
case AuthSession::PlayableOnline:
{
launchInstance();
tryagain = false;
return;
} }
m_session->MakeOffline(usedname);
// offline flavored game from here :3
}
case AuthSession::PlayableOnline:
{
launchInstance();
tryagain = false;
return;
}
} }
} }
emitFailed(tr("Failed to launch."));*/ emitFailed(tr("Failed to launch."));
} }
void LaunchController::launchInstance() void LaunchController::launchInstance()

View File

@@ -43,13 +43,22 @@ void LoginDialog::accept()
// Setup the login task and start it // Setup the login task and start it
m_account = MojangAccount::createFromUsername(ui->userTextBox->text()); m_account = MojangAccount::createFromUsername(ui->userTextBox->text());
if (ui->radioMojang->isChecked())
m_account->setLoginType("mojang");
else if (ui->radioDummy->isChecked())
m_account->setLoginType("dummy");
m_loginTask = m_account->login(nullptr, ui->passTextBox->text()); m_loginTask = m_account->login(nullptr, ui->passTextBox->text());
connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::failed, this, &LoginDialog::onTaskFailed);
connect(m_loginTask.get(), &Task::succeeded, this, connect(m_loginTask.get(), &Task::succeeded, this,
&LoginDialog::onTaskSucceeded); &LoginDialog::onTaskSucceeded);
connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus); connect(m_loginTask.get(), &Task::status, this, &LoginDialog::onTaskStatus);
connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress); connect(m_loginTask.get(), &Task::progress, this, &LoginDialog::onTaskProgress);
m_loginTask->start(); if (!m_loginTask)
{
onTaskSucceeded();
} else {
m_loginTask->start();
}
} }
void LoginDialog::setUserInputsEnabled(bool enable) void LoginDialog::setUserInputsEnabled(bool enable)

View File

@@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>400</width> <width>400</width>
<height>162</height> <height>219</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@@ -60,6 +60,30 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QVBoxLayout" name="radioLayout">
<item>
<widget class="QRadioButton" name="radioMojang">
<property name="text">
<string>Mojang / Minecraft</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioDummy">
<property name="text">
<string>Offline (cracked)</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox"> <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation"> <property name="orientation">