diff options
| -rw-r--r-- | src/nexusmanualkey.ui | 156 | ||||
| -rw-r--r-- | src/settings.cpp | 78 | ||||
| -rw-r--r-- | src/settings.h | 30 | ||||
| -rw-r--r-- | src/settingsdialog.cpp | 129 | ||||
| -rw-r--r-- | src/settingsdialog.h | 93 | ||||
| -rw-r--r-- | src/settingsdialog.ui | 4 |
6 files changed, 337 insertions, 153 deletions
diff --git a/src/nexusmanualkey.ui b/src/nexusmanualkey.ui index 191ca218..1a842dc3 100644 --- a/src/nexusmanualkey.ui +++ b/src/nexusmanualkey.ui @@ -7,16 +7,16 @@ <x>0</x> <y>0</y> <width>452</width> - <height>302</height> + <height>236</height> </rect> </property> <property name="windowTitle"> <string>Dialog</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0"> <item> <widget class="QWidget" name="widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0"> <property name="leftMargin"> <number>0</number> </property> @@ -30,10 +30,152 @@ <number>0</number> </property> <item> - <widget class="QPlainTextEdit" name="key"> - <property name="placeholderText"> - <string>Enter API key here</string> - </property> + <widget class="QWidget" name="widget_2" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>1. Get your personal API key</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="openBrowser"> + <property name="text"> + <string>Open Browser</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="widget_3" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,1"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QWidget" name="widget_4" native="true"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>2. Enter your personal API key</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>115</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="paste"> + <property name="text"> + <string>Paste</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="clear"> + <property name="text"> + <string>Clear</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QPlainTextEdit" name="key"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Ignored" vsizetype="Ignored"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>1</width> + <height>1</height> + </size> + </property> + <property name="placeholderText"> + <string>Enter API key here</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QWidget" name="widget_5" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string><b>Sharing this key with anyone could get your Nexus account banned. You can always revoke this key from your account on the Nexus website.</b></string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> </widget> </item> </layout> diff --git a/src/settings.cpp b/src/settings.cpp index a844fdc9..53dd32dc 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -363,6 +363,32 @@ bool Settings::getNexusApiKey(QString &apiKey) const return true; } +bool Settings::setNexusApiKey(const QString& apiKey) +{ + if (!obfuscate("APIKEY", apiKey)) { + wchar_t buffer[256]; + + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); + + qCritical() << "Storing API key failed:" << buffer; + return false; + } + + return true; +} + +bool Settings::clearNexusApiKey() +{ + return setNexusApiKey(""); +} + +bool Settings::hasNexusApiKey() const +{ + return !deObfuscate("APIKEY").isEmpty(); +} + bool Settings::getSteamLogin(QString &username, QString &password) const { if (m_Settings.contains("Settings/steam_username")) { @@ -452,17 +478,6 @@ QString Settings::executablesBlacklist() const ).toString(); } -void Settings::setNexusApiKey(QString apiKey) -{ - if (!obfuscate("APIKEY", apiKey)) { - wchar_t buffer[256]; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); - qCritical() << "Storing API key failed:" << buffer; - } -} - void Settings::setSteamLogin(QString username, QString password) { if (username == "") { @@ -706,43 +721,10 @@ void Settings::resetDialogs() QuestionBoxMemory::resetDialogs(); } -void Settings::processApiKey(const QString &apiKey) -{ - if (!obfuscate("APIKEY", apiKey)) { - wchar_t buffer[256]; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - buffer, (sizeof(buffer) / sizeof(wchar_t)), NULL); - qCritical() << "Storing or deleting API key failed:" << buffer; - } -} - -void Settings::clearApiKey(QPushButton *nexusButton) -{ - obfuscate("APIKEY", ""); - nexusButton->setEnabled(true); - nexusButton->setText("Connect to Nexus"); -} - -void Settings::checkApiKey(QPushButton *nexusButton) -{ - if (deObfuscate("APIKEY").isEmpty()) { - nexusButton->setEnabled(true); - nexusButton->setText("Connect to Nexus"); - QMessageBox::warning(qApp->activeWindow(), tr("Error"), - tr("Failed to retrieve a Nexus API key! Please try again. " - "A browser window should open asking you to authorize.")); - } -} - void Settings::query(PluginContainer *pluginContainer, QWidget *parent) { - SettingsDialog dialog(pluginContainer, parent); - + SettingsDialog dialog(pluginContainer, this, parent); connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs())); - connect(&dialog, SIGNAL(processApiKey(const QString &)), this, SLOT(processApiKey(const QString &))); - connect(&dialog, SIGNAL(closeApiConnection(QPushButton *)), this, SLOT(checkApiKey(QPushButton *))); - connect(&dialog, SIGNAL(revokeApiKey(QPushButton *)), this, SLOT(clearApiKey(QPushButton *))); std::vector<std::unique_ptr<SettingsTab>> tabs; @@ -1043,7 +1025,6 @@ void Settings::DiagnosticsTab::update() Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) : Settings::SettingsTab(parent, dialog) - , m_nexusConnect(dialog.findChild<QPushButton *>("nexusConnect")) , m_offlineBox(dialog.findChild<QCheckBox *>("offlineBox")) , m_proxyBox(dialog.findChild<QCheckBox *>("proxyBox")) , m_knownServersList(dialog.findChild<QListWidget *>("knownServersList")) @@ -1052,11 +1033,6 @@ Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) , m_endorsementBox(dialog.findChild<QCheckBox *>("endorsementBox")) , m_hideAPICounterBox(dialog.findChild<QCheckBox *>("hideAPICounterBox")) { - if (!deObfuscate("APIKEY").isEmpty()) { - m_nexusConnect->setText("Nexus API Key Stored"); - m_nexusConnect->setDisabled(true); - } - m_offlineBox->setChecked(parent->offlineMode()); m_proxyBox->setChecked(parent->useProxy()); m_endorsementBox->setChecked(parent->endorsementIntegration()); diff --git a/src/settings.h b/src/settings.h index 04a0646e..bccd1e81 100644 --- a/src/settings.h +++ b/src/settings.h @@ -188,6 +188,24 @@ public: bool getNexusApiKey(QString &apiKey) const; /** + * @brief set the nexus login information + * + * @param username username + * @param password password + */ + bool setNexusApiKey(const QString& apiKey); + + /** + * @brief clears the nexus login information + */ + bool clearNexusApiKey(); + + /** + * @brief returns whether an API key is currently stored + */ + bool hasNexusApiKey() const; + + /** * @brief retrieve the login information for steam * * @param username (out) receives the user name for nexus @@ -241,14 +259,6 @@ public: QString executablesBlacklist() const; /** - * @brief set the nexus login information - * - * @param username username - * @param password password - */ - void setNexusApiKey(QString apiKey); - - /** * @brief set the steam login information * * @param username username @@ -481,7 +491,6 @@ private: void update(); private: - QPushButton *m_nexusConnect; QCheckBox *m_offlineBox; QCheckBox *m_proxyBox; QListWidget *m_knownServersList; @@ -538,9 +547,6 @@ private: private slots: void resetDialogs(); - void processApiKey(const QString &); - void clearApiKey(QPushButton *nexusButton); - void checkApiKey(QPushButton *nexusButton); signals: diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 44d7fde5..0373cef6 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -57,6 +57,10 @@ public: : QDialog(parent), ui(new Ui::NexusManualKeyDialog) { ui->setupUi(this); + + connect(ui->openBrowser, &QPushButton::clicked, [&]{ openBrowser(); }); + connect(ui->paste, &QPushButton::clicked, [&]{ paste(); }); + connect(ui->clear, &QPushButton::clicked, [&]{ clear(); }); } void accept() override @@ -70,15 +74,34 @@ public: return m_key; } + void openBrowser() + { + shell::OpenLink(QUrl("https://www.nexusmods.com/users/myaccount?tab=api")); + } + + void paste() + { + const auto text = QApplication::clipboard()->text(); + if (!text.isEmpty()) { + ui->key->setPlainText(text); + } + } + + void clear() + { + ui->key->clear(); + } + private: std::unique_ptr<Ui::NexusManualKeyDialog> ui; QString m_key; }; -SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, QWidget *parent) +SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, Settings* settings, QWidget *parent) : TutorableDialog("SettingsDialog", parent) , ui(new Ui::SettingsDialog) + , m_settings(settings) , m_PluginContainer(pluginContainer) , m_nexusLogin(new QWebSocket) , m_KeyReceived(false) @@ -95,8 +118,9 @@ SettingsDialog::SettingsDialog(PluginContainer *pluginContainer, QWidget *parent connect(m_nexusLogin, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(authError(QAbstractSocket::SocketError))); connect(m_nexusLogin, SIGNAL(textMessageReceived(const QString &)), this, SLOT(receiveApiKey(const QString &))); connect(m_nexusLogin, SIGNAL(disconnected()), this, SLOT(completeApiConnection())); - connect(this, SIGNAL(retryApiConnection()), this, SLOT(on_nexusConnect_clicked())); m_loginTimer.callOnTimeout(this, &SettingsDialog::loginPing); + + updateNexusButtons(); } SettingsDialog::~SettingsDialog() @@ -367,10 +391,7 @@ void SettingsDialog::on_resetDialogsButton_clicked() void SettingsDialog::on_nexusConnect_clicked() { - ui->nexusConnect->setText("Connecting the API. Please login within the browser and accept the request. This will time out after 30 minutes."); - ui->nexusConnect->setDisabled(true); - QUrl url = QUrl("wss://sso.nexusmods.com"); - m_nexusLogin->open(url); + fetchNexusApiKey(); } void SettingsDialog::on_nexusManualKey_clicked() @@ -382,9 +403,21 @@ void SettingsDialog::on_nexusManualKey_clicked() } const auto key = dialog.key(); - emit processApiKey(key); - ui->nexusConnect->setText("Nexus API Key Stored"); - NexusInterface::instance(m_PluginContainer)->getAccessManager()->apiCheck(key, true); + + if (key.isEmpty()) { + clearKey(); + } else { + if (setKey(key)) { + testApiKey(); + } + } +} + +void SettingsDialog::fetchNexusApiKey() +{ + QUrl url = QUrl("wss://sso.nexusmods.com"); + m_nexusLogin->open(url); + updateNexusButtons(); } void SettingsDialog::dispatchLogin() @@ -434,12 +467,17 @@ void SettingsDialog::receiveApiKey(const QString &response) if (data.contains("connection_token")) { m_AuthToken = data["connection_token"].toString(); } else { - m_KeyReceived = true; - emit processApiKey(data["api_key"].toString()); + const auto key = data["api_key"].toString(); + m_nexusLogin->close(); - ui->nexusConnect->setText("Nexus API Key Stored"); m_loginTimer.stop(); m_totalPings = 0; + + if (key.isEmpty()) { + clearKey(); + } else { + setKey(key); + } } } else { QString error("There was a problem with SSO initialization: %1"); @@ -450,10 +488,64 @@ void SettingsDialog::receiveApiKey(const QString &response) void SettingsDialog::completeApiConnection() { - if (m_KeyReceived == true || !m_loginTimer.isActive()) - emit closeApiConnection(ui->nexusConnect); - else - emit retryApiConnection(); + if (!m_KeyReceived && !m_loginTimer.isActive()) { + QMessageBox::warning(qApp->activeWindow(), tr("Error"), + tr("Failed to retrieve a Nexus API key! Please try again. " + "A browser window should open asking you to authorize.")); + + // try again + fetchNexusApiKey(); + } +} + +bool SettingsDialog::setKey(const QString& key) +{ + m_KeyReceived = true; + const bool ret = m_settings->setNexusApiKey(key); + updateNexusButtons(); + return ret; +} + +bool SettingsDialog::clearKey() +{ + m_KeyCleared = true; + const auto ret = m_settings->clearNexusApiKey(); + updateNexusButtons(); + return ret; +} + +void SettingsDialog::testApiKey() +{ + QString key; + if (!m_settings->getNexusApiKey(key)) { + qWarning().nospace() << "can't test API key, nothing stored"; + return; + } + + auto* am = NexusInterface::instance(m_PluginContainer)->getAccessManager(); + am->apiCheck(key, true); +} + +void SettingsDialog::updateNexusButtons() +{ + if (m_nexusLogin->state() != QAbstractSocket::UnconnectedState) { + // api key is in the process of being retrieved + ui->nexusConnect->setText("Connecting the API. Please login within the browser and accept the request. This will time out after 30 minutes."); + ui->nexusConnect->setEnabled(false); + } + else if (m_settings->hasNexusApiKey()) { + // api key is present + ui->nexusConnect->setText("Nexus API Key Stored"); + ui->nexusConnect->setEnabled(false); + ui->nexusDisconnect->setEnabled(true); + ui->nexusManualKey->setEnabled(false); + } else { + // api key not present + ui->nexusConnect->setText("Connect to Nexus"); + ui->nexusConnect->setEnabled(true); + ui->nexusDisconnect->setEnabled(false); + ui->nexusManualKey->setEnabled(true); + } } void SettingsDialog::storeSettings(QListWidgetItem *pluginItem) @@ -523,10 +615,9 @@ void SettingsDialog::on_clearCacheButton_clicked() NexusInterface::instance(m_PluginContainer)->clearCache(); } -void SettingsDialog::on_revokeNexusAuthButton_clicked() +void SettingsDialog::on_nexusDisconnect_clicked() { - emit revokeApiKey(ui->nexusConnect); - m_KeyCleared = true; + clearKey(); } void SettingsDialog::normalizePath(QLineEdit *lineEdit) diff --git a/src/settingsdialog.h b/src/settingsdialog.h index a844b391..858a36d4 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -29,6 +29,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QTimer> class PluginContainer; +class Settings; namespace Ui { class SettingsDialog; @@ -44,7 +45,9 @@ class SettingsDialog : public MOBase::TutorableDialog Q_OBJECT public: - explicit SettingsDialog(PluginContainer *pluginContainer, QWidget *parent = 0); + explicit SettingsDialog( + PluginContainer *pluginContainer, Settings* settings, QWidget *parent = 0); + ~SettingsDialog(); /** @@ -62,9 +65,6 @@ public slots: signals: void resetDialogs(); - void processApiKey(const QString &); - void closeApiConnection(QPushButton *); - void revokeApiKey(QPushButton *); void retryApiConnection(); private: @@ -94,105 +94,74 @@ public: private slots: - //void on_loginCheckBox_toggled(bool checked); - void on_categoriesBtn_clicked(); - void on_execBlacklistBtn_clicked(); - void on_bsaDateBtn_clicked(); - void on_browseDownloadDirBtn_clicked(); - void on_browseModDirBtn_clicked(); - void on_browseCacheDirBtn_clicked(); - void on_resetDialogsButton_clicked(); - void on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); - - void deleteBlacklistItem(); - void on_associateButton_clicked(); - void on_clearCacheButton_clicked(); - - void on_revokeNexusAuthButton_clicked(); - + void on_nexusDisconnect_clicked(); void on_browseBaseDirBtn_clicked(); - void on_browseOverwriteDirBtn_clicked(); - void on_browseProfilesDirBtn_clicked(); - void on_browseGameDirBtn_clicked(); - void on_overwritingBtn_clicked(); - void on_overwrittenBtn_clicked(); - void on_overwritingArchiveBtn_clicked(); - void on_overwrittenArchiveBtn_clicked(); - void on_containsBtn_clicked(); - void on_containedBtn_clicked(); - void on_resetColorsBtn_clicked(); - void on_baseDirEdit_editingFinished(); - void on_downloadDirEdit_editingFinished(); - void on_modDirEdit_editingFinished(); - void on_cacheDirEdit_editingFinished(); - void on_profilesDirEdit_editingFinished(); - void on_overwriteDirEdit_editingFinished(); - void on_nexusConnect_clicked(); - void on_nexusManualKey_clicked(); + void on_resetGeometryBtn_clicked(); + void deleteBlacklistItem(); void dispatchLogin(); - void loginPing(); - void authError(QAbstractSocket::SocketError error); - void receiveApiKey(const QString &apiKey); - void completeApiConnection(); - void on_resetGeometryBtn_clicked(); - private: - Ui::SettingsDialog *ui; - PluginContainer *m_PluginContainer; + Ui::SettingsDialog *ui; + Settings* m_settings; + PluginContainer *m_PluginContainer; - QColor m_OverwritingColor; - QColor m_OverwrittenColor; - QColor m_OverwritingArchiveColor; - QColor m_OverwrittenArchiveColor; - QColor m_ContainsColor; - QColor m_ContainedColor; + QColor m_OverwritingColor; + QColor m_OverwrittenColor; + QColor m_OverwritingArchiveColor; + QColor m_OverwrittenArchiveColor; + QColor m_ContainsColor; + QColor m_ContainedColor; - bool m_KeyReceived; - bool m_KeyCleared; - bool m_GeometriesReset; - QString m_UUID; - QString m_AuthToken; + bool m_KeyReceived; + bool m_KeyCleared; + bool m_GeometriesReset; + QString m_UUID; + QString m_AuthToken; - QString m_ExecutableBlacklist; - QWebSocket *m_nexusLogin; - QTimer m_loginTimer; - int m_totalPings = 0; -}; + QString m_ExecutableBlacklist; + QWebSocket *m_nexusLogin; + QTimer m_loginTimer; + int m_totalPings = 0; + bool setKey(const QString& key); + bool clearKey(); + void updateNexusButtons(); + void fetchNexusApiKey(); + void testApiKey(); +}; #endif // SETTINGSDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 088b7a0d..08c8d9f2 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -511,12 +511,12 @@ p, li { white-space: pre-wrap; } </widget> </item> <item> - <widget class="QPushButton" name="revokeNexusAuthButton"> + <widget class="QPushButton" name="nexusDisconnect"> <property name="toolTip"> <string>Clear the stored Nexus API key and force reauthorization.</string> </property> <property name="text"> - <string>Revoke Nexus Authorization</string> + <string>Disconnect from Nexus</string> </property> <property name="icon"> <iconset resource="resources.qrc"> |
