Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorJonathan White <support@dmapps.us>2020-04-06 15:42:20 +0300
committerJonathan White <support@dmapps.us>2020-05-15 03:19:56 +0300
commit51429810189cf17501b925712920f9340ec4f4d1 (patch)
tree7ff60339527e885a1924cc525ceb4007f6596f22 /src/gui
parenta145bf91191f0a4630a7e31654aff8a8dfd09bf0 (diff)
Significantly enhance hardware key robustness
* Significantly improve user experience when using hardware keys on databases in both GUI and CLI modes. Prevent locking up the YubiKey USB interface for prolonged periods of time. Allows for other apps to use the key concurrently with KeePassXC. * Improve messages displayed to user when finding keys and when user interaction is required. Output specific error messages when handling hardware keys during database read/write. * Only poll for keys when previously used or upon user request. Prevent continuously polling keys when accessing the UI such as switching tabs and minimize/maximize. * Add support for using multiple hardware keys simultaneously. Keys are identified by their serial number which prevents using the wrong key during open and save operations. * Fixes #4400 * Fixes #4065 * Fixes #1050 * Fixes #1215 * Fixes #3087 * Fixes #1088 * Fixes #1869
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/ApplicationSettingsWidget.cpp1
-rw-r--r--src/gui/DatabaseOpenWidget.cpp166
-rw-r--r--src/gui/DatabaseOpenWidget.h11
-rw-r--r--src/gui/DatabaseOpenWidget.ui12
-rw-r--r--src/gui/DatabaseWidget.cpp4
-rw-r--r--src/gui/MainWindow.cpp9
-rw-r--r--src/gui/masterkey/YubiKeyEditWidget.cpp93
-rw-r--r--src/gui/masterkey/YubiKeyEditWidget.h6
8 files changed, 144 insertions, 158 deletions
diff --git a/src/gui/ApplicationSettingsWidget.cpp b/src/gui/ApplicationSettingsWidget.cpp
index 9d1f45d49..72905c0b2 100644
--- a/src/gui/ApplicationSettingsWidget.cpp
+++ b/src/gui/ApplicationSettingsWidget.cpp
@@ -391,6 +391,7 @@ void ApplicationSettingsWidget::saveSettings()
if (!config()->get(Config::RememberLastKeyFiles).toBool()) {
config()->remove(Config::LastKeyFiles);
+ config()->remove(Config::LastChallengeResponse);
config()->remove(Config::LastDir);
}
diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp
index 1b1c74cd5..cef92d2d4 100644
--- a/src/gui/DatabaseOpenWidget.cpp
+++ b/src/gui/DatabaseOpenWidget.cpp
@@ -37,7 +37,6 @@
#include <QDesktopServices>
#include <QFont>
#include <QSharedPointer>
-#include <QtConcurrentRun>
DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
: DialogyWidget(parent)
@@ -73,18 +72,29 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
connect(m_ui->keyFileClearIcon, SIGNAL(triggered(bool)), SLOT(clearKeyFileEdit()));
#ifdef WITH_XC_YUBIKEY
- m_ui->yubikeyProgress->setVisible(false);
- QSizePolicy sp = m_ui->yubikeyProgress->sizePolicy();
+ m_ui->hardwareKeyProgress->setVisible(false);
+ QSizePolicy sp = m_ui->hardwareKeyProgress->sizePolicy();
sp.setRetainSizeWhenHidden(true);
- m_ui->yubikeyProgress->setSizePolicy(sp);
+ m_ui->hardwareKeyProgress->setSizePolicy(sp);
- connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey()));
+ connect(m_ui->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollHardwareKey()));
+ connect(YubiKey::instance(), SIGNAL(detectComplete(bool)), SLOT(hardwareKeyResponse(bool)), Qt::QueuedConnection);
+
+ connect(YubiKey::instance(), &YubiKey::userInteractionRequest, this, [this] {
+ // Show the press notification if we are in an independent window (e.g., DatabaseOpenDialog)
+ if (window() != getMainWindow()) {
+ m_ui->messageWidget->showMessage(tr("Please touch the button on your YubiKey!"),
+ MessageWidget::Information,
+ MessageWidget::DisableAutoHide);
+ }
+ });
+ connect(YubiKey::instance(), &YubiKey::challengeCompleted, this, [this] { m_ui->messageWidget->hide(); });
#else
m_ui->hardwareKeyLabel->setVisible(false);
m_ui->hardwareKeyLabelHelp->setVisible(false);
m_ui->buttonRedetectYubikey->setVisible(false);
- m_ui->comboChallengeResponse->setVisible(false);
- m_ui->yubikeyProgress->setVisible(false);
+ m_ui->challengeResponseCombo->setVisible(false);
+ m_ui->hardwareKeyProgress->setVisible(false);
#endif
#ifndef WITH_XC_TOUCHID
@@ -104,37 +114,16 @@ void DatabaseOpenWidget::showEvent(QShowEvent* event)
{
DialogyWidget::showEvent(event);
m_ui->editPassword->setFocus();
-
-#ifdef WITH_XC_YUBIKEY
- // showEvent() may be called twice, so make sure we are only polling once
- if (!m_yubiKeyBeingPolled) {
- // clang-format off
- connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection);
- connect(YubiKey::instance(), SIGNAL(detectComplete()), SLOT(yubikeyDetectComplete()), Qt::QueuedConnection);
- connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection);
- // clang-format on
-
- pollYubikey();
- m_yubiKeyBeingPolled = true;
- }
-#endif
}
void DatabaseOpenWidget::hideEvent(QHideEvent* event)
{
DialogyWidget::hideEvent(event);
-#ifdef WITH_XC_YUBIKEY
- // Don't listen to any Yubikey events if we are hidden
- disconnect(YubiKey::instance(), nullptr, this, nullptr);
- m_yubiKeyBeingPolled = false;
-#endif
-
- if (isVisible()) {
- return;
+ // Clear the forms if we are minimized
+ if (!isVisible()) {
+ clearForms();
}
-
- clearForms();
}
void DatabaseOpenWidget::load(const QString& filename)
@@ -148,7 +137,7 @@ void DatabaseOpenWidget::load(const QString& filename)
m_keyFileComboEdited = false;
if (config()->get(Config::RememberLastKeyFiles).toBool()) {
- QHash<QString, QVariant> lastKeyFiles = config()->get(Config::LastKeyFiles).toHash();
+ auto lastKeyFiles = config()->get(Config::LastKeyFiles).toHash();
if (lastKeyFiles.contains(m_filename)) {
m_ui->comboKeyFile->addItem(lastKeyFiles[m_filename].toString());
m_ui->comboKeyFile->setCurrentIndex(1);
@@ -157,6 +146,16 @@ void DatabaseOpenWidget::load(const QString& filename)
QHash<QString, QVariant> useTouchID = config()->get(Config::UseTouchID).toHash();
m_ui->checkTouchID->setChecked(useTouchID.value(m_filename, false).toBool());
+
+#ifdef WITH_XC_YUBIKEY
+ // Only auto-poll for hardware keys if we previously used one with this database file
+ if (config()->get(Config::RememberLastKeyFiles).toBool()) {
+ auto lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash();
+ if (lastChallengeResponse.contains(m_filename)) {
+ pollHardwareKey();
+ }
+ }
+#endif
}
void DatabaseOpenWidget::clearForms()
@@ -176,6 +175,11 @@ QSharedPointer<Database> DatabaseOpenWidget::database()
return m_db;
}
+QString DatabaseOpenWidget::filename()
+{
+ return m_filename;
+}
+
void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile)
{
m_ui->editPassword->setText(pw);
@@ -186,6 +190,8 @@ void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile)
void DatabaseOpenWidget::openDatabase()
{
+ m_ui->messageWidget->hide();
+
QSharedPointer<CompositeKey> masterKey = databaseKey();
if (!masterKey) {
return;
@@ -223,11 +229,6 @@ void DatabaseOpenWidget::openDatabase()
config()->set(Config::UseTouchID, useTouchID);
#endif
-
- if (m_ui->messageWidget->isVisible()) {
- m_ui->messageWidget->animatedHide();
- }
-
emit dialogFinished(true);
m_isOpeningDatabase = false;
clearForms();
@@ -293,7 +294,7 @@ QSharedPointer<CompositeKey> DatabaseOpenWidget::databaseKey()
}
#endif
- QHash<QString, QVariant> lastKeyFiles = config()->get(Config::LastKeyFiles).toHash();
+ auto lastKeyFiles = config()->get(Config::LastKeyFiles).toHash();
lastKeyFiles.remove(m_filename);
auto key = QSharedPointer<FileKey>::create();
@@ -315,14 +316,14 @@ QSharedPointer<CompositeKey> DatabaseOpenWidget::databaseKey()
legacyWarning.setDefaultButton(QMessageBox::Ok);
legacyWarning.setCheckBox(new QCheckBox(tr("Don't show this warning again")));
- connect(legacyWarning.checkBox(), &QCheckBox::stateChanged, [](int state) {
+ connect(legacyWarning.checkBox(), &QCheckBox::stateChanged, this, [](int state) {
config()->set(Config::Messages_NoLegacyKeyFileWarning, state == Qt::CheckState::Checked);
});
legacyWarning.exec();
}
masterKey->addKey(key);
- lastKeyFiles[m_filename] = keyFilename;
+ lastKeyFiles.insert(m_filename, keyFilename);
}
if (config()->get(Config::RememberLastKeyFiles).toBool()) {
@@ -330,19 +331,17 @@ QSharedPointer<CompositeKey> DatabaseOpenWidget::databaseKey()
}
#ifdef WITH_XC_YUBIKEY
- QHash<QString, QVariant> lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash();
+ auto lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash();
lastChallengeResponse.remove(m_filename);
- int selectionIndex = m_ui->comboChallengeResponse->currentIndex();
+ int selectionIndex = m_ui->challengeResponseCombo->currentIndex();
if (selectionIndex > 0) {
- int comboPayload = m_ui->comboChallengeResponse->itemData(selectionIndex).toInt();
-
- // read blocking mode from LSB and slot index number from second LSB
- bool blocking = comboPayload & 1;
- int slot = comboPayload >> 1;
- auto crKey = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
+ auto slot = m_ui->challengeResponseCombo->itemData(selectionIndex).value<YubiKeySlot>();
+ auto crKey = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot));
masterKey->addChallengeResponseKey(crKey);
- lastChallengeResponse[m_filename] = true;
+
+ // Qt doesn't read custom types in settings so stuff into a QString
+ lastChallengeResponse.insert(m_filename, QStringLiteral("%1:%2").arg(slot.first).arg(slot.second));
}
if (config()->get(Config::RememberLastKeyFiles).toBool()) {
@@ -400,45 +399,62 @@ void DatabaseOpenWidget::handleKeyFileComboChanged()
m_ui->keyFileClearIcon->setVisible(m_keyFileComboEdited);
}
-void DatabaseOpenWidget::pollYubikey()
+void DatabaseOpenWidget::pollHardwareKey()
{
+ if (m_pollingHardwareKey) {
+ return;
+ }
+
+ m_ui->challengeResponseCombo->clear();
+ m_ui->challengeResponseCombo->addItem(tr("Detecting hardware keys…"));
+
m_ui->buttonRedetectYubikey->setEnabled(false);
- m_ui->comboChallengeResponse->setEnabled(false);
- m_ui->comboChallengeResponse->clear();
- m_ui->comboChallengeResponse->addItem(tr("Select slot..."), -1);
- m_ui->yubikeyProgress->setVisible(true);
+ m_ui->challengeResponseCombo->setEnabled(false);
+ m_ui->hardwareKeyProgress->setVisible(true);
+ m_pollingHardwareKey = true;
- // YubiKey init is slow, detect asynchronously to not block the UI
- QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
+ YubiKey::instance()->findValidKeys();
}
-void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking)
+void DatabaseOpenWidget::hardwareKeyResponse(bool found)
{
- YkChallengeResponseKey yk(slot, blocking);
- // add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB
- m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1) | blocking));
+ m_ui->challengeResponseCombo->clear();
+ m_ui->buttonRedetectYubikey->setEnabled(true);
+ m_ui->hardwareKeyProgress->setVisible(false);
+ m_pollingHardwareKey = false;
+ if (!found) {
+ m_ui->challengeResponseCombo->addItem(tr("No hardware keys detected"));
+ m_ui->challengeResponseCombo->setEnabled(false);
+ return;
+ } else {
+ m_ui->challengeResponseCombo->addItem(tr("Select hardware key…"));
+ }
+
+ YubiKeySlot lastUsedSlot;
if (config()->get(Config::RememberLastKeyFiles).toBool()) {
- QHash<QString, QVariant> lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash();
+ auto lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash();
if (lastChallengeResponse.contains(m_filename)) {
- m_ui->comboChallengeResponse->setCurrentIndex(1);
+ // Qt doesn't read custom types in settings so extract from QString
+ auto split = lastChallengeResponse.value(m_filename).toString().split(":");
+ if (split.size() > 1) {
+ lastUsedSlot = YubiKeySlot(split[0].toUInt(), split[1].toInt());
+ }
}
}
-}
-void DatabaseOpenWidget::yubikeyDetectComplete()
-{
- m_ui->comboChallengeResponse->setEnabled(true);
- m_ui->buttonRedetectYubikey->setEnabled(true);
- m_ui->yubikeyProgress->setVisible(false);
- m_yubiKeyBeingPolled = false;
-}
+ int selectedIndex = 0;
+ for (auto& slot : YubiKey::instance()->foundKeys()) {
+ // add detected YubiKey to combo box
+ m_ui->challengeResponseCombo->addItem(YubiKey::instance()->getDisplayName(slot), QVariant::fromValue(slot));
+ // Select this YubiKey + Slot if we used it in the past
+ if (lastUsedSlot == slot) {
+ selectedIndex = m_ui->challengeResponseCombo->count() - 1;
+ }
+ }
-void DatabaseOpenWidget::noYubikeyFound()
-{
- m_ui->buttonRedetectYubikey->setEnabled(true);
- m_ui->yubikeyProgress->setVisible(false);
- m_yubiKeyBeingPolled = false;
+ m_ui->challengeResponseCombo->setCurrentIndex(selectedIndex);
+ m_ui->challengeResponseCombo->setEnabled(true);
}
void DatabaseOpenWidget::openHardwareKeyHelp()
diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h
index 61a220f43..487bc9d3c 100644
--- a/src/gui/DatabaseOpenWidget.h
+++ b/src/gui/DatabaseOpenWidget.h
@@ -40,13 +40,11 @@ public:
explicit DatabaseOpenWidget(QWidget* parent = nullptr);
~DatabaseOpenWidget();
void load(const QString& filename);
+ QString filename();
void clearForms();
void enterKey(const QString& pw, const QString& keyFile);
QSharedPointer<Database> database();
-public slots:
- void pollYubikey();
-
signals:
void dialogFinished(bool accepted);
@@ -64,9 +62,8 @@ private slots:
void clearKeyFileEdit();
void handleKeyFileComboEdited();
void handleKeyFileComboChanged();
- void yubikeyDetected(int slot, bool blocking);
- void yubikeyDetectComplete();
- void noYubikeyFound();
+ void pollHardwareKey();
+ void hardwareKeyResponse(bool found);
void openHardwareKeyHelp();
void openKeyFileHelp();
@@ -77,7 +74,7 @@ protected:
bool m_retryUnlockWithEmptyPassword = false;
private:
- bool m_yubiKeyBeingPolled = false;
+ bool m_pollingHardwareKey = false;
bool m_keyFileComboEdited = false;
bool m_isOpeningDatabase = false;
Q_DISABLE_COPY(DatabaseOpenWidget)
diff --git a/src/gui/DatabaseOpenWidget.ui b/src/gui/DatabaseOpenWidget.ui
index f89e30ffd..278d45c47 100644
--- a/src/gui/DatabaseOpenWidget.ui
+++ b/src/gui/DatabaseOpenWidget.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>580</width>
- <height>410</height>
+ <width>588</width>
+ <height>448</height>
</rect>
</property>
<property name="accessibleName">
@@ -280,7 +280,7 @@
<number>0</number>
</property>
<item row="1" column="2">
- <widget class="QProgressBar" name="yubikeyProgress">
+ <widget class="QProgressBar" name="hardwareKeyProgress">
<property name="maximumSize">
<size>
<width>16777215</width>
@@ -302,7 +302,7 @@
</widget>
</item>
<item row="0" column="2">
- <widget class="QComboBox" name="comboChallengeResponse">
+ <widget class="QComboBox" name="challengeResponseCombo">
<property name="enabled">
<bool>false</bool>
</property>
@@ -338,7 +338,7 @@
<string>Hardware Key:</string>
</property>
<property name="buddy">
- <cstring>comboChallengeResponse</cstring>
+ <cstring>challengeResponseCombo</cstring>
</property>
</widget>
</item>
@@ -606,7 +606,7 @@
<tabstop>comboKeyFile</tabstop>
<tabstop>buttonBrowseFile</tabstop>
<tabstop>hardwareKeyLabelHelp</tabstop>
- <tabstop>comboChallengeResponse</tabstop>
+ <tabstop>challengeResponseCombo</tabstop>
<tabstop>checkTouchID</tabstop>
</tabstops>
<resources/>
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 2b30d6e01..d28f73714 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -1183,7 +1183,9 @@ void DatabaseWidget::switchToDatabaseSettings()
void DatabaseWidget::switchToOpenDatabase()
{
- switchToOpenDatabase(m_db->filePath());
+ if (currentWidget() != m_databaseOpenWidget || m_databaseOpenWidget->filename() != m_db->filePath()) {
+ switchToOpenDatabase(m_db->filePath());
+ }
}
void DatabaseWidget::switchToOpenDatabase(const QString& filePath)
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index a94229376..3d129bb94 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -68,6 +68,10 @@
#include "fdosecrets/FdoSecretsPlugin.h"
#endif
+#ifdef WITH_XC_YUBIKEY
+#include "keys/drivers/YubiKey.h"
+#endif
+
#ifdef WITH_XC_BROWSER
#include "browser/BrowserService.h"
#include "browser/BrowserSettingsPage.h"
@@ -175,6 +179,11 @@ MainWindow::MainWindow()
m_ui->settingsWidget->addSettingsPage(fdoSS);
#endif
+#ifdef WITH_XC_YUBIKEY
+ connect(YubiKey::instance(), SIGNAL(userInteractionRequest()), SLOT(showYubiKeyPopup()), Qt::QueuedConnection);
+ connect(YubiKey::instance(), SIGNAL(challengeCompleted()), SLOT(hideYubiKeyPopup()), Qt::QueuedConnection);
+#endif
+
setWindowIcon(resources()->applicationIcon());
m_ui->globalMessageWidget->setHidden(true);
// clang-format off
diff --git a/src/gui/masterkey/YubiKeyEditWidget.cpp b/src/gui/masterkey/YubiKeyEditWidget.cpp
index 9ecd918ef..855bd7099 100644
--- a/src/gui/masterkey/YubiKeyEditWidget.cpp
+++ b/src/gui/masterkey/YubiKeyEditWidget.cpp
@@ -19,13 +19,12 @@
#include "ui_YubiKeyEditWidget.h"
#include "config-keepassx.h"
+#include "core/AsyncTask.h"
#include "gui/MainWindow.h"
#include "gui/MessageBox.h"
#include "keys/CompositeKey.h"
#include "keys/YkChallengeResponseKey.h"
-#include <QtConcurrent>
-
YubiKeyEditWidget::YubiKeyEditWidget(QWidget* parent)
: KeyComponentWidget(parent)
, m_compUi(new Ui::YubiKeyEditWidget())
@@ -36,6 +35,8 @@ YubiKeyEditWidget::YubiKeyEditWidget(QWidget* parent)
"for additional security.</p><p>The YubiKey requires one of its slots to be programmed as "
"<a href=\"https://www.yubico.com/products/services-software/personalization-tools/challenge-response/\">"
"HMAC-SHA1 Challenge-Response</a>.</p>"));
+
+ connect(YubiKey::instance(), SIGNAL(detectComplete(bool)), SLOT(hardwareKeyResponse(bool)), Qt::QueuedConnection);
}
YubiKeyEditWidget::~YubiKeyEditWidget()
@@ -44,24 +45,31 @@ YubiKeyEditWidget::~YubiKeyEditWidget()
bool YubiKeyEditWidget::addToCompositeKey(QSharedPointer<CompositeKey> key)
{
- QSharedPointer<YkChallengeResponseKey> keyPtr;
- if (!createCrKey(keyPtr, false)) {
+ if (!m_isDetected || !m_compEditWidget) {
return false;
}
- key->addChallengeResponseKey(keyPtr);
+ int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();
+ auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();
+ key->addChallengeResponseKey(QSharedPointer<YkChallengeResponseKey>::create(slot));
return true;
}
bool YubiKeyEditWidget::validate(QString& errorMessage) const
{
- QSharedPointer<YkChallengeResponseKey> keyPtr;
- if (!createCrKey(keyPtr)) {
- errorMessage = tr("No YubiKey detected, please ensure it's plugged in.");
+ if (!m_isDetected) {
+ errorMessage = tr("Could not find any hardware keys!");
return false;
}
- return true;
+ // Perform a test challenge response
+ int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();
+ auto slot = m_compUi->comboChallengeResponse->itemData(selectionIndex).value<YubiKeySlot>();
+ bool valid = AsyncTask::runAndWaitForFuture([&slot] { return YubiKey::instance()->testChallenge(slot); });
+ if (!valid) {
+ errorMessage = tr("Selected hardware key slot does not support challenge-response!");
+ }
+ return valid;
}
QWidget* YubiKeyEditWidget::componentEditWidget()
@@ -76,13 +84,6 @@ QWidget* YubiKeyEditWidget::componentEditWidget()
#ifdef WITH_XC_YUBIKEY
connect(m_compUi->buttonRedetectYubikey, SIGNAL(clicked()), SLOT(pollYubikey()));
-
- // clang-format off
- connect(YubiKey::instance(), SIGNAL(detected(int,bool)), SLOT(yubikeyDetected(int,bool)), Qt::QueuedConnection);
- connect(YubiKey::instance(), SIGNAL(detectComplete()), SLOT(yubikeyDetectComplete()), Qt::QueuedConnection);
- connect(YubiKey::instance(), SIGNAL(notFound()), SLOT(noYubikeyFound()), Qt::QueuedConnection);
- // clang-format on
-
pollYubikey();
#endif
@@ -105,72 +106,36 @@ void YubiKeyEditWidget::pollYubikey()
m_isDetected = false;
m_compUi->comboChallengeResponse->clear();
+ m_compUi->comboChallengeResponse->addItem(tr("Detecting hardware keys…"));
m_compUi->buttonRedetectYubikey->setEnabled(false);
m_compUi->comboChallengeResponse->setEnabled(false);
m_compUi->yubikeyProgress->setVisible(true);
- // YubiKey init is slow, detect asynchronously to not block the UI
- QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
+ YubiKey::instance()->findValidKeys();
#endif
}
-void YubiKeyEditWidget::yubikeyDetected(int slot, bool blocking)
+void YubiKeyEditWidget::hardwareKeyResponse(bool found)
{
-#ifdef WITH_XC_YUBIKEY
if (!m_compEditWidget) {
return;
}
- YkChallengeResponseKey yk(slot, blocking);
- // add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB
- m_compUi->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1u) | blocking));
- m_isDetected = true;
-#else
- Q_UNUSED(slot);
- Q_UNUSED(blocking);
-#endif
-}
-
-void YubiKeyEditWidget::yubikeyDetectComplete()
-{
- m_compUi->comboChallengeResponse->setEnabled(true);
- m_compUi->buttonRedetectYubikey->setEnabled(true);
- m_compUi->yubikeyProgress->setVisible(false);
-}
-void YubiKeyEditWidget::noYubikeyFound()
-{
-#ifdef WITH_XC_YUBIKEY
- if (!m_compEditWidget) {
- return;
- }
m_compUi->comboChallengeResponse->clear();
- m_compUi->comboChallengeResponse->setEnabled(false);
- m_compUi->comboChallengeResponse->addItem(tr("No YubiKey inserted."));
m_compUi->buttonRedetectYubikey->setEnabled(true);
m_compUi->yubikeyProgress->setVisible(false);
- m_isDetected = false;
-#endif
-}
-bool YubiKeyEditWidget::createCrKey(QSharedPointer<YkChallengeResponseKey>& key, bool testChallenge) const
-{
- Q_ASSERT(m_compEditWidget);
- if (!m_isDetected || !m_compEditWidget) {
- return false;
+ if (!found) {
+ m_compUi->comboChallengeResponse->addItem(tr("No hardware keys detected"));
+ m_isDetected = false;
+ return;
}
- int selectionIndex = m_compUi->comboChallengeResponse->currentIndex();
- int comboPayload = m_compUi->comboChallengeResponse->itemData(selectionIndex).toInt();
-
- if (0 == comboPayload) {
- return false;
+ for (auto& slot : YubiKey::instance()->foundKeys()) {
+ // add detected YubiKey to combo box and encode blocking mode in LSB, slot number in second LSB
+ m_compUi->comboChallengeResponse->addItem(YubiKey::instance()->getDisplayName(slot), QVariant::fromValue(slot));
}
- auto blocking = static_cast<bool>(comboPayload & 1u);
- int slot = comboPayload >> 1u;
- key.reset(new YkChallengeResponseKey(slot, blocking));
- if (testChallenge) {
- return key->challenge(QByteArray("0000"));
- }
- return true;
+ m_isDetected = true;
+ m_compUi->comboChallengeResponse->setEnabled(true);
}
diff --git a/src/gui/masterkey/YubiKeyEditWidget.h b/src/gui/masterkey/YubiKeyEditWidget.h
index 549f7f44f..d5be0a683 100644
--- a/src/gui/masterkey/YubiKeyEditWidget.h
+++ b/src/gui/masterkey/YubiKeyEditWidget.h
@@ -45,14 +45,10 @@ protected:
void initComponentEditWidget(QWidget* widget) override;
private slots:
- void yubikeyDetected(int slot, bool blocking);
- void yubikeyDetectComplete();
- void noYubikeyFound();
+ void hardwareKeyResponse(bool found);
void pollYubikey();
private:
- bool createCrKey(QSharedPointer<YkChallengeResponseKey>& key, bool testChallenge = true) const;
-
const QScopedPointer<Ui::YubiKeyEditWidget> m_compUi;
QPointer<QWidget> m_compEditWidget;
bool m_isDetected = false;