diff --git a/src/gui/Application.cpp b/src/gui/Application.cpp index 26d9d2283..4c84fda86 100644 --- a/src/gui/Application.cpp +++ b/src/gui/Application.cpp @@ -87,6 +87,11 @@ Application::Application(int& argc, char** argv) #endif } +QWidget* Application::mainWindow() const +{ + return m_mainWindow; +} + void Application::setMainWindow(QWidget* mainWindow) { m_mainWindow = mainWindow; diff --git a/src/gui/Application.h b/src/gui/Application.h index 9bfe4d549..c6f4aae66 100644 --- a/src/gui/Application.h +++ b/src/gui/Application.h @@ -29,6 +29,7 @@ class Application : public QApplication public: Application(int& argc, char** argv); + QWidget* mainWindow() const; void setMainWindow(QWidget* mainWindow); bool event(QEvent* event) override; diff --git a/src/gui/ChangeMasterKeyWidget.cpp b/src/gui/ChangeMasterKeyWidget.cpp index 453498a17..b223d3922 100644 --- a/src/gui/ChangeMasterKeyWidget.cpp +++ b/src/gui/ChangeMasterKeyWidget.cpp @@ -25,6 +25,7 @@ #include "gui/FileDialog.h" #include "gui/MessageBox.h" #include "crypto/Random.h" +#include "MainWindow.h" #include "config-keepassx.h" @@ -176,6 +177,8 @@ void ChangeMasterKeyWidget::generateKey() bool blocking = i & true; int slot = i >> 1; auto key = QSharedPointer(new YkChallengeResponseKey(slot, blocking)); + connect(key.data(), SIGNAL(userInteractionRequired()), SLOT(showYubiKeyPopup())); + connect(key.data(), SIGNAL(userConfirmed()), SLOT(hideYubiKeyPopup())); m_key.addChallengeResponseKey(key); } #endif @@ -238,3 +241,15 @@ void ChangeMasterKeyWidget::setCancelEnabled(bool enabled) { m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(enabled); } + +void ChangeMasterKeyWidget::showYubiKeyPopup() +{ + KEEPASSXC_MAIN_WINDOW->displayGlobalMessage(tr("Please touch the button on your YubiKey!"), MessageWidget::Information); + KEEPASSXC_MAIN_WINDOW->setEnabled(false); +} + +void ChangeMasterKeyWidget::hideYubiKeyPopup() +{ + KEEPASSXC_MAIN_WINDOW->hideGlobalMessage(); + KEEPASSXC_MAIN_WINDOW->setEnabled(true); +} diff --git a/src/gui/ChangeMasterKeyWidget.h b/src/gui/ChangeMasterKeyWidget.h index b3e097276..fdc7f9529 100644 --- a/src/gui/ChangeMasterKeyWidget.h +++ b/src/gui/ChangeMasterKeyWidget.h @@ -55,6 +55,8 @@ private slots: void noYubikeyFound(); void challengeResponseGroupToggled(bool checked); void pollYubikey(); + void showYubiKeyPopup(); + void hideYubiKeyPopup(); private: const QScopedPointer m_ui; diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 2eebcae3c..03a560c2f 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -214,6 +214,8 @@ CompositeKey DatabaseOpenWidget::databaseKey() bool blocking = i & true; int slot = i >> 1; auto key = QSharedPointer(new YkChallengeResponseKey(slot, blocking)); + connect(key.data(), SIGNAL(userInteractionRequired()), SLOT(showYubiKeyPopup())); + connect(key.data(), SIGNAL(userConfirmed()), SLOT(hideYubiKeyPopup())); masterKey.addChallengeResponseKey(key); } #endif @@ -264,6 +266,18 @@ void DatabaseOpenWidget::pollYubikey() QtConcurrent::run(YubiKey::instance(), &YubiKey::detect); } +void DatabaseOpenWidget::showYubiKeyPopup() +{ + m_ui->messageWidget->showMessage(tr("Please touch the button on your YubiKey!"), MessageWidget::Information); + KEEPASSXC_MAIN_WINDOW->setEnabled(false); +} + +void DatabaseOpenWidget::hideYubiKeyPopup() +{ + m_ui->messageWidget->hideMessage(); + KEEPASSXC_MAIN_WINDOW->setEnabled(true); +} + void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) { YkChallengeResponseKey yk(slot, blocking); diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h index caba70a61..eee705a79 100644 --- a/src/gui/DatabaseOpenWidget.h +++ b/src/gui/DatabaseOpenWidget.h @@ -53,6 +53,8 @@ protected: protected slots: virtual void openDatabase(); + void showYubiKeyPopup(); + void hideYubiKeyPopup(); void reject(); private slots: diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 694b38e7a..c3262a3cc 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -24,6 +24,7 @@ #include "core/SignalMultiplexer.h" #include "gui/DatabaseWidget.h" +#include "gui/Application.h" namespace Ui { class MainWindow; @@ -43,6 +44,9 @@ public Q_SLOTS: void openDatabase(const QString& fileName, const QString& pw = QString(), const QString& keyFile = QString()); void appExit(); + void displayGlobalMessage(const QString& text, MessageWidget::MessageType type); + void displayTabMessage(const QString& text, MessageWidget::MessageType type); + void hideGlobalMessage(); protected: void closeEvent(QCloseEvent* event) override; @@ -75,9 +79,6 @@ private Q_SLOTS: void toggleWindow(); void lockDatabasesAfterInactivity(); void repairDatabase(); - void displayGlobalMessage(const QString& text, MessageWidget::MessageType type); - void displayTabMessage(const QString& text, MessageWidget::MessageType type); - void hideGlobalMessage(); void hideTabMessage(); private: @@ -106,4 +107,6 @@ private: bool appExitCalled; }; +#define KEEPASSXC_MAIN_WINDOW qobject_cast(qobject_cast(qApp)->mainWindow()) + #endif // KEEPASSX_MAINWINDOW_H diff --git a/src/keys/YkChallengeResponseKey.cpp b/src/keys/YkChallengeResponseKey.cpp index a6e5cdbcf..039d7a1e6 100644 --- a/src/keys/YkChallengeResponseKey.cpp +++ b/src/keys/YkChallengeResponseKey.cpp @@ -14,16 +14,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -#include -#include +#include "keys/YkChallengeResponseKey.h" +#include "keys/drivers/YubiKey.h" #include "core/Tools.h" #include "crypto/CryptoHash.h" #include "crypto/Random.h" -#include "keys/YkChallengeResponseKey.h" -#include "keys/drivers/YubiKey.h" +#include +#include +#include +#include +#include +#include YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking) : m_slot(slot), @@ -39,12 +42,12 @@ QByteArray YkChallengeResponseKey::rawKey() const /** * Assumes yubikey()->init() was called */ -bool YkChallengeResponseKey::challenge(const QByteArray& chal) +bool YkChallengeResponseKey::challenge(const QByteArray& challenge) { - return challenge(chal, 1); + return this->challenge(challenge, 1); } -#include -bool YkChallengeResponseKey::challenge(const QByteArray& chal, unsigned retries) + +bool YkChallengeResponseKey::challenge(const QByteArray& challenge, unsigned retries) { Q_ASSERT(retries > 0); @@ -55,13 +58,21 @@ bool YkChallengeResponseKey::challenge(const QByteArray& chal, unsigned retries) emit userInteractionRequired(); } - auto result = YubiKey::instance()->challenge(m_slot, true, chal, m_key); + QFuture future = QtConcurrent::run([this, challenge]() { + return YubiKey::instance()->challenge(m_slot, true, challenge, m_key); + }); + + QEventLoop loop; + QFutureWatcher watcher; + watcher.setFuture(future); + connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); if (m_blocking) { emit userConfirmed(); } - if (result != YubiKey::ERROR) { + if (future.result() != YubiKey::ERROR) { return true; } diff --git a/src/keys/YkChallengeResponseKey.h b/src/keys/YkChallengeResponseKey.h index 96e44220d..8c566ca41 100644 --- a/src/keys/YkChallengeResponseKey.h +++ b/src/keys/YkChallengeResponseKey.h @@ -33,8 +33,8 @@ public: YkChallengeResponseKey(int slot = -1, bool blocking = false); QByteArray rawKey() const; - bool challenge(const QByteArray& chal); - bool challenge(const QByteArray& chal, unsigned retries); + bool challenge(const QByteArray& challenge); + bool challenge(const QByteArray& challenge, unsigned retries); QString getName() const; bool isBlocking() const; diff --git a/src/keys/drivers/YubiKey.cpp b/src/keys/drivers/YubiKey.cpp index e68949394..bab0d7215 100644 --- a/src/keys/drivers/YubiKey.cpp +++ b/src/keys/drivers/YubiKey.cpp @@ -182,6 +182,7 @@ YubiKey::ChallengeResult YubiKey::challenge(int slot, bool mayBlock, const QByte #endif int ret = yk_challenge_response(m_yk, yk_cmd, mayBlock, paddedChallenge.size(), c, response.size(), r); + emit challenged(); m_mutex.unlock(); diff --git a/src/keys/drivers/YubiKey.h b/src/keys/drivers/YubiKey.h index 2382b69cf..b938ff86b 100644 --- a/src/keys/drivers/YubiKey.h +++ b/src/keys/drivers/YubiKey.h @@ -86,6 +86,11 @@ Q_SIGNALS: */ void detected(int slot, bool blocking); + /** + * Emitted when the YubiKey was challenged and has returned a response. + */ + void challenged(); + /** * Emitted when no Yubikey could be found. */