Verify access tokens before launching Minecraft

Kind of an important thing to do... Heh...
This commit is contained in:
Andrew
2013-11-28 20:45:52 -06:00
parent 1f150dcb78
commit bfc9e1e5d5
12 changed files with 440 additions and 73 deletions

View File

@@ -60,6 +60,7 @@
#include "gui/dialogs/CopyInstanceDialog.h"
#include "gui/dialogs/AccountListDialog.h"
#include "gui/dialogs/AccountSelectDialog.h"
#include "gui/dialogs/PasswordDialog.h"
#include "gui/ConsoleWindow.h"
@@ -69,6 +70,9 @@
#include "logic/lists/IconList.h"
#include "logic/lists/JavaVersionList.h"
#include "logic/auth/AuthenticateTask.h"
#include "logic/auth/ValidateTask.h"
#include "logic/net/LoginTask.h"
#include "logic/BaseInstance.h"
@@ -709,7 +713,7 @@ void MainWindow::instanceActivated(QModelIndex index)
NagUtils::checkJVMArgs(inst->settings().get("JvmArgs").toString(), this);
doLogin();
doLaunch();
}
void MainWindow::on_actionLaunchInstance_triggered()
@@ -717,11 +721,11 @@ void MainWindow::on_actionLaunchInstance_triggered()
if (m_selectedInstance)
{
NagUtils::checkJVMArgs(m_selectedInstance->settings().get("JvmArgs").toString(), this);
doLogin();
doLaunch();
}
}
void MainWindow::doLogin(const QString &errorMsg)
void MainWindow::doLaunch()
{
if (!m_selectedInstance)
return;
@@ -761,11 +765,69 @@ void MainWindow::doLogin(const QString &errorMsg)
if (account.get() != nullptr)
{
// We'll need to validate the access token to make sure the account is still logged in.
// TODO: Do that ^
doLaunchInst(m_selectedInstance, account);
}
}
void MainWindow::doLaunchInst(BaseInstance* instance, MojangAccountPtr account)
{
// We'll need to validate the access token to make sure the account is still logged in.
ProgressDialog progDialog(this);
ValidateTask validateTask(account, &progDialog);
progDialog.exec(&validateTask);
if (validateTask.successful())
{
prepareLaunch(m_selectedInstance, account);
}
else
{
YggdrasilTask::Error* error = validateTask.getError();
if (error != nullptr)
{
if (error->getErrorMessage().contains("invalid token", Qt::CaseInsensitive))
{
// TODO: Allow the user to enter their password and "refresh" their access token.
if (doRefreshToken(account, tr("Your account's access token is invalid. Please enter your password to log in again.")))
doLaunchInst(instance, account);
}
else
{
CustomMessageBox::selectable(this, tr("Access Token Validation Error"),
tr("There was an error when trying to validate your access token.\n"
"Details: %s").arg(error->getDisplayMessage()),
QMessageBox::Warning, QMessageBox::Ok)->exec();
}
}
else
{
CustomMessageBox::selectable(this, tr("Access Token Validation Error"),
tr("There was an unknown error when trying to validate your access token."
"The authentication server might be down, or you might not be connected to the Internet."),
QMessageBox::Warning, QMessageBox::Ok)->exec();
}
}
}
bool MainWindow::doRefreshToken(MojangAccountPtr account, const QString& errorMsg)
{
PasswordDialog passDialog(errorMsg, this);
if (passDialog.exec() == QDialog::Accepted)
{
// To refresh the token, we just create an authenticate task with the given account and the user's password.
ProgressDialog progDialog(this);
AuthenticateTask authTask(account, passDialog.password(), &progDialog);
progDialog.exec(&authTask);
if (authTask.successful())
return true;
else
{
// If the authentication task failed, recurse with the task's error message.
return doRefreshToken(account, authTask.failReason());
}
}
else return false;
}
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)

View File

@@ -106,7 +106,23 @@ slots:
void on_actionEditInstNotes_triggered();
void doLogin(const QString &errorMsg = "");
/*!
* Launches the currently selected instance with the default account.
* If no default account is selected, prompts the user to pick an account.
*/
void doLaunch();
/*!
* Launches the given instance with the given account.
*/
void doLaunchInst(BaseInstance* instance, MojangAccountPtr account);
/*!
* Opens an input dialog, allowing the user to input their password and refresh its access token.
* This function will execute the proper Yggdrasil task to refresh the access token.
* Returns true if successful. False if the user cancelled.
*/
bool doRefreshToken(MojangAccountPtr account, const QString& errorMsg="");
/*!
* Launches the given instance with the given account.

View File

@@ -0,0 +1,38 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PasswordDialog.h"
#include "ui_PasswordDialog.h"
PasswordDialog::PasswordDialog(const QString& errorMsg, QWidget *parent) :
QDialog(parent),
ui(new Ui::PasswordDialog)
{
ui->setupUi(this);
ui->errorLabel->setText(errorMsg);
ui->errorLabel->setVisible(!errorMsg.isEmpty());
}
PasswordDialog::~PasswordDialog()
{
delete ui;
}
QString PasswordDialog::password() const
{
return ui->passTextBox->text();
}

View File

@@ -0,0 +1,40 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QDialog>
namespace Ui {
class PasswordDialog;
}
class PasswordDialog : public QDialog
{
Q_OBJECT
public:
explicit PasswordDialog(const QString& errorMsg="", QWidget *parent = 0);
~PasswordDialog();
/*!
* Gets the text entered in the dialog's password field.
*/
QString password() const;
private:
Ui::PasswordDialog *ui;
};

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PasswordDialog</class>
<widget class="QDialog" name="PasswordDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>94</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="errorLabel">
<property name="text">
<string>Error message here...</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="passTextBox">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PasswordDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PasswordDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>