summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-07-11 02:31:59 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2019-07-11 02:31:59 -0400
commitad29525e982f83343dbd70e17b914e0a30adb662 (patch)
tree09ee6531679787412b3e16bcdbbe6156a20f9a8c
parent5e5681709ab878f3aa6cf1344af44e8ae9544987 (diff)
moved NexusSSOLogin to nxmaccessmanager
added logs for manual key validation, will need to rewrite a few things
-rw-r--r--src/nxmaccessmanager.cpp166
-rw-r--r--src/nxmaccessmanager.h64
-rw-r--r--src/settingsdialog.cpp198
-rw-r--r--src/settingsdialog.h52
4 files changed, 250 insertions, 230 deletions
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index 8bbfd536..a274261d 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -44,6 +44,8 @@ using namespace std::chrono_literals;
const QString NexusBaseUrl("https://api.nexusmods.com/v1");
const std::chrono::seconds NXMAccessManager::ValidationTimeout = 10s;
+const QString NexusSSO("wss://sso.nexusmods.com");
+const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
ValidationProgressDialog::ValidationProgressDialog(std::chrono::seconds t)
@@ -94,7 +96,10 @@ void ValidationProgressDialog::start()
void ValidationProgressDialog::stop()
{
- m_timer->stop();
+ if (m_timer) {
+ m_timer->stop();
+ }
+
hide();
}
@@ -119,6 +124,153 @@ void ValidationProgressDialog::onTimer()
}
+NexusSSOLogin::NexusSSOLogin()
+ : m_keyReceived(false), m_active(false)
+{
+ QObject::connect(
+ &m_socket, &QWebSocket::connected,
+ [&]{ onConnected(); });
+
+ QObject::connect(
+ &m_socket, qOverload<QAbstractSocket::SocketError>(&QWebSocket::error),
+ [&](auto&& e){ onError(e); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::textMessageReceived,
+ [&](auto&& s){ onMessage(s); });
+
+ QObject::connect(
+ &m_socket, &QWebSocket::disconnected,
+ [&]{ onDisconnected(); });
+
+ QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
+}
+
+void NexusSSOLogin::start()
+{
+ m_active = true;
+ setState(ConnectingToSSO);
+ m_timeout.start(NXMAccessManager::ValidationTimeout);
+ m_socket.open(NexusSSO);
+}
+
+void NexusSSOLogin::cancel()
+{
+ abort();
+ setState(Cancelled);
+}
+
+void NexusSSOLogin::close()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.close();
+}
+
+void NexusSSOLogin::abort()
+{
+ m_active = false;
+ m_timeout.stop();
+ m_socket.abort();
+}
+
+bool NexusSSOLogin::isActive() const
+{
+ return m_active;
+}
+
+void NexusSSOLogin::setState(States s, const QString& error)
+{
+ if (stateChanged) {
+ stateChanged(s, error);
+ }
+}
+
+void NexusSSOLogin::onConnected()
+{
+ setState(WaitingForToken);
+
+ m_keyReceived = false;
+
+ //if (m_guid.isEmpty()) {
+ boost::uuids::random_generator generator;
+ boost::uuids::uuid sessionId = generator();
+ m_guid = boost::uuids::to_string(sessionId).c_str();
+ //}
+
+ QJsonObject data;
+ data.insert(QString("id"), QJsonValue(m_guid));
+ //data.insert(QString("token"), QJsonValue(m_token));
+ data.insert(QString("protocol"), 2);
+
+ const QString message = QJsonDocument(data).toJson();
+ m_socket.sendTextMessage(message);
+}
+
+void NexusSSOLogin::onMessage(const QString& s)
+{
+ const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8());
+ const QVariantMap root = doc.object().toVariantMap();
+
+ if (!root["success"].toBool()) {
+ close();
+
+ setState(Error, QString("There was a problem with SSO initialization: %1")
+ .arg(root["error"].toString()));
+
+ return;
+ }
+
+ const QVariantMap data = root["data"].toMap();
+
+ if (data.contains("connection_token")) {
+ // first answer
+ m_token = data["connection_token"].toString();
+
+ // open browser
+ const auto url = NexusSSOPage.arg(m_guid);
+ shell::OpenLink(url);
+
+ m_timeout.stop();
+ setState(WaitingForBrowser);
+ } else {
+ // second answer
+ const auto key = data["api_key"].toString();
+ close();
+
+ if (keyChanged) {
+ keyChanged(key);
+ }
+
+ setState(Finished);
+ }
+}
+
+void NexusSSOLogin::onDisconnected()
+{
+ if (m_active) {
+ m_active = false;
+
+ if (!m_keyReceived) {
+ setState(ClosedByRemote);
+ }
+ }
+}
+
+void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
+{
+ if (m_active) {
+ setState(Error, m_socket.errorString());
+ }
+}
+
+void NexusSSOLogin::onTimeout()
+{
+ abort();
+ setState(Timeout);
+}
+
+
NXMAccessManager::NXMAccessManager(QObject *parent, const QString &moVersion)
: QNetworkAccessManager(parent)
, m_ValidateReply(nullptr)
@@ -192,7 +344,7 @@ void NXMAccessManager::clearCookies()
}
}
-void NXMAccessManager::startValidationCheck()
+void NXMAccessManager::startValidationCheck(bool showProgress)
{
qDebug("Checking Nexus API Key...");
QString requestString = NexusBaseUrl + "/users/validate";
@@ -205,7 +357,9 @@ void NXMAccessManager::startValidationCheck()
request.setRawHeader("Application-Name", "MO2");
request.setRawHeader("Application-Version", m_MOVersion.toUtf8());
- m_ProgressDialog->start();
+ if (showProgress) {
+ m_ProgressDialog->start();
+ }
QCoreApplication::processEvents(); // for some reason the whole app hangs during the login. This way the user has at least a little feedback
@@ -245,13 +399,13 @@ bool NXMAccessManager::validateWaiting() const
}
-void NXMAccessManager::apiCheck(const QString &apiKey, bool force)
+void NXMAccessManager::apiCheck(const QString &apiKey, ApiCheckFlags flags)
{
if (m_ValidateReply != nullptr) {
return;
}
- if (force) {
+ if (flags & Force) {
m_ValidateState = VALIDATE_NOT_CHECKED;
}
@@ -261,7 +415,7 @@ void NXMAccessManager::apiCheck(const QString &apiKey, bool force)
}
m_ApiKey = apiKey;
- startValidationCheck();
+ startValidationCheck((flags & HideProgress) == 0);
}
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index cbec0530..08a799f9 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QProgressDialog>
#include <QElapsedTimer>
#include <QDialogButtonBox>
+#include <QWebSocket>
#include <set>
namespace MOBase { class IPluginGame; }
@@ -60,6 +61,52 @@ private:
};
+class NexusSSOLogin
+{
+public:
+ enum States
+ {
+ ConnectingToSSO,
+ WaitingForToken,
+ WaitingForBrowser,
+ Finished,
+ Timeout,
+ ClosedByRemote,
+ Cancelled,
+ Error
+ };
+
+ std::function<void (QString)> keyChanged;
+ std::function<void (States, QString)> stateChanged;
+
+ NexusSSOLogin();
+
+ void start();
+ void cancel();
+
+ bool isActive() const;
+
+private:
+ QWebSocket m_socket;
+ QString m_guid;
+ bool m_keyReceived;
+ QString m_token;
+ bool m_active;
+ QTimer m_timeout;
+
+ void setState(States s, const QString& error={});
+
+ void close();
+ void abort();
+
+ void onConnected();
+ void onMessage(const QString& s);
+ void onDisconnected();
+ void onError(QAbstractSocket::SocketError e);
+ void onTimeout();
+};
+
+
/**
* @brief access manager extended to handle nxm links
**/
@@ -67,6 +114,15 @@ class NXMAccessManager : public QNetworkAccessManager
{
Q_OBJECT
public:
+ enum ApiCheckFlagsEnum
+ {
+ NoFlags = 0,
+ Force,
+ HideProgress
+ };
+
+ Q_DECLARE_FLAGS(ApiCheckFlags, ApiCheckFlagsEnum)
+
static const std::chrono::seconds ValidationTimeout;
explicit NXMAccessManager(QObject *parent, const QString &moVersion);
@@ -80,7 +136,7 @@ public:
bool validateAttempted() const;
bool validateWaiting() const;
- void apiCheck(const QString &apiKey, bool force=false);
+ void apiCheck(const QString &apiKey, ApiCheckFlags flags=NoFlags);
void showCookies() const;
@@ -91,8 +147,6 @@ public:
QString apiKey() const;
void clearApiKey();
- void startValidationCheck();
-
void refuseValidation();
signals:
@@ -145,6 +199,10 @@ private:
VALIDATE_REFUSED,
VALIDATE_VALID
} m_ValidateState = VALIDATE_NOT_CHECKED;
+
+ void startValidationCheck(bool showProgress);
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(NXMAccessManager::ApiCheckFlags);
+
#endif // NXMACCESSMANAGER_H
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index d1ace6a5..0131d20b 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -28,7 +28,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "settings.h"
#include "instancemanager.h"
#include "nexusinterface.h"
-#include "nxmaccessmanager.h"
#include "plugincontainer.h"
#include <boost/uuid/uuid_generators.hpp>
@@ -49,9 +48,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
-const QString NexusSSO("wss://sso.nexusmods.com");
-const QString NexusSSOPage("https://www.nexusmods.com/sso?id=%1&application=modorganizer2");
-
class NexusManualKeyDialog : public QDialog
{
public:
@@ -100,154 +96,6 @@ private:
};
-
-NexusSSOLogin::NexusSSOLogin()
- : m_keyReceived(false), m_active(false)
-{
- QObject::connect(
- &m_socket, &QWebSocket::connected,
- [&]{ onConnected(); });
-
- QObject::connect(
- &m_socket, qOverload<QAbstractSocket::SocketError>(&QWebSocket::error),
- [&](auto&& e){ onError(e); });
-
- QObject::connect(
- &m_socket, &QWebSocket::textMessageReceived,
- [&](auto&& s){ onMessage(s); });
-
- QObject::connect(
- &m_socket, &QWebSocket::disconnected,
- [&]{ onDisconnected(); });
-
- QObject::connect(&m_timeout, &QTimer::timeout, [&]{ onTimeout(); });
-}
-
-void NexusSSOLogin::start()
-{
- m_active = true;
- setState(ConnectingToSSO);
- m_timeout.start(NXMAccessManager::ValidationTimeout);
- m_socket.open(NexusSSO);
-}
-
-void NexusSSOLogin::cancel()
-{
- abort();
- setState(Cancelled);
-}
-
-void NexusSSOLogin::close()
-{
- m_active = false;
- m_timeout.stop();
- m_socket.close();
-}
-
-void NexusSSOLogin::abort()
-{
- m_active = false;
- m_timeout.stop();
- m_socket.abort();
-}
-
-bool NexusSSOLogin::isActive() const
-{
- return m_active;
-}
-
-void NexusSSOLogin::setState(States s, const QString& error)
-{
- if (stateChanged) {
- stateChanged(s, error);
- }
-}
-
-void NexusSSOLogin::onConnected()
-{
- setState(WaitingForToken);
-
- m_keyReceived = false;
-
- //if (m_guid.isEmpty()) {
- boost::uuids::random_generator generator;
- boost::uuids::uuid sessionId = generator();
- m_guid = boost::uuids::to_string(sessionId).c_str();
- //}
-
- QJsonObject data;
- data.insert(QString("id"), QJsonValue(m_guid));
- //data.insert(QString("token"), QJsonValue(m_token));
- data.insert(QString("protocol"), 2);
-
- const QString message = QJsonDocument(data).toJson();
- m_socket.sendTextMessage(message);
-}
-
-void NexusSSOLogin::onMessage(const QString& s)
-{
- const QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8());
- const QVariantMap root = doc.object().toVariantMap();
-
- if (!root["success"].toBool()) {
- close();
-
- setState(Error, QString("There was a problem with SSO initialization: %1")
- .arg(root["error"].toString()));
-
- return;
- }
-
- const QVariantMap data = root["data"].toMap();
-
- if (data.contains("connection_token")) {
- // first answer
- m_token = data["connection_token"].toString();
-
- // open browser
- const auto url = NexusSSOPage.arg(m_guid);
- shell::OpenLink(url);
-
- m_timeout.stop();
- setState(WaitingForBrowser);
- } else {
- // second answer
- const auto key = data["api_key"].toString();
- close();
-
- if (keyChanged) {
- keyChanged(key);
- }
-
- setState(Finished);
- }
-}
-
-void NexusSSOLogin::onDisconnected()
-{
- if (m_active) {
- m_active = false;
-
- if (!m_keyReceived) {
- setState(ClosedByRemote);
- }
- }
-}
-
-void NexusSSOLogin::onError(QAbstractSocket::SocketError e)
-{
- if (m_active) {
- setState(Error, m_socket.errorString());
- }
-}
-
-void NexusSSOLogin::onTimeout()
-{
- abort();
- setState(Timeout);
-}
-
-
SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent)
: TutorableDialog("SettingsDialog", parent)
, ui(new Ui::SettingsDialog)
@@ -259,11 +107,22 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* setti
m_nexusLogin.keyChanged = [&](auto&& s){ onKeyChanged(s); };
m_nexusLogin.stateChanged = [&](auto&& s, auto&& e){ onStateChanged(s, e); };
+ connect(
+ NexusInterface::instance(m_PluginContainer)->getAccessManager(),
+ &NXMAccessManager::validateSuccessful,
+ [&]{ onManualKeyValidation(true, ""); });
+
+ connect(
+ NexusInterface::instance(m_PluginContainer)->getAccessManager(),
+ &NXMAccessManager::validateFailed,
+ [&](auto&& e){ onManualKeyValidation(false, e); });
+
+
ui->setupUi(this);
ui->pluginSettingsList->setStyleSheet("QTreeWidget::item {padding-right: 10px;}");
- QShortcut *delShortcut
- = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
+ QShortcut *delShortcut = new QShortcut(
+ QKeySequence(Qt::Key_Delete), ui->pluginBlacklist);
connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem()));
updateNexusButtons();
@@ -556,7 +415,11 @@ void SettingsDialog::on_nexusManualKey_clicked()
clearKey();
} else {
if (setKey(key)) {
- testApiKey();
+ ui->nexusLog->clear();
+ ui->nexusLog->addItem(tr("Checking API key..."));
+
+ NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(
+ key, NXMAccessManager::Force | NXMAccessManager::HideProgress);
}
}
}
@@ -583,11 +446,6 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e)
switch (s)
{
- case NexusSSOLogin::Idle:
- {
- break;
- }
-
case NexusSSOLogin::ConnectingToSSO:
{
log = tr("Connecting to Nexus...");
@@ -649,6 +507,15 @@ void SettingsDialog::onStateChanged(NexusSSOLogin::States s, const QString& e)
updateNexusButtons();
}
+void SettingsDialog::onManualKeyValidation(bool success, const QString& e)
+{
+ if (success) {
+ ui->nexusLog->addItem("Connected.");
+ } else {
+ ui->nexusLog->addItem("Error: " + e);
+ }
+}
+
bool SettingsDialog::setKey(const QString& key)
{
m_keyChanged = true;
@@ -668,17 +535,6 @@ bool SettingsDialog::clearKey()
return ret;
}
-void SettingsDialog::testApiKey()
-{
- QString key;
- if (!m_settings->getNexusApiKey(key)) {
- qWarning().nospace() << "can't test API key, nothing stored";
- return;
- }
-
- NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true);
-}
-
void SettingsDialog::updateNexusButtons()
{
if (m_nexusLogin.isActive()) {
diff --git a/src/settingsdialog.h b/src/settingsdialog.h
index aee447d7..507214dd 100644
--- a/src/settingsdialog.h
+++ b/src/settingsdialog.h
@@ -21,12 +21,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define SETTINGSDIALOG_H
#include "tutorabledialog.h"
+#include "nxmaccessmanager.h"
#include <iplugin.h>
-#include <QComboBox>
-#include <QDialog>
-#include <QWebSocket>
#include <QListWidgetItem>
-#include <QTimer>
class PluginContainer;
class Settings;
@@ -35,51 +32,6 @@ namespace Ui {
class SettingsDialog;
}
-class NexusSSOLogin
-{
-public:
- enum States
- {
- Idle,
- ConnectingToSSO,
- WaitingForToken,
- WaitingForBrowser,
- Finished,
- Timeout,
- ClosedByRemote,
- Cancelled,
- Error
- };
-
- std::function<void (QString)> keyChanged;
- std::function<void (States, QString)> stateChanged;
-
- NexusSSOLogin();
-
- void start();
- void cancel();
-
- bool isActive() const;
-
-private:
- QWebSocket m_socket;
- QString m_guid;
- bool m_keyReceived;
- QString m_token;
- bool m_active;
- QTimer m_timeout;
-
- void setState(States s, const QString& error={});
-
- void close();
- void abort();
-
- void onConnected();
- void onMessage(const QString& s);
- void onDisconnected();
- void onError(QAbstractSocket::SocketError e);
- void onTimeout();
-};
/**
* dialog used to change settings for Mod Organizer. On top of the
@@ -197,9 +149,9 @@ private:
void updateNexusButtons();
void fetchNexusApiKey();
- void testApiKey();
void onKeyChanged(const QString& key);
void onStateChanged(NexusSSOLogin::States s, const QString& e);
+ void onManualKeyValidation(bool success, const QString& e);
};
#endif // SETTINGSDIALOG_H