diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 7cf5dcb15..a1f2e1e7d 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -326,7 +326,7 @@ QString DatabaseOpenWidget::filename() return m_filename; } -void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile) +void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile, const QString& yubikey) { if (unlockingDatabase()) { qWarning("Ignoring unlock request for %s because of running unlock action.", qPrintable(m_filename)); @@ -335,11 +335,12 @@ void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile) m_ui->editPassword->setText(pw); m_ui->keyFileLineEdit->setText(keyFile); + m_blockQuickUnlock = true; - openDatabase(); + openDatabase(yubikey); } -void DatabaseOpenWidget::openDatabase() +void DatabaseOpenWidget::openDatabase(const QString& yubikey) { // Cache this variable for future use then reset bool blockQuickUnlock = m_blockQuickUnlock || isOnQuickUnlockScreen(); @@ -350,7 +351,7 @@ void DatabaseOpenWidget::openDatabase() m_ui->messageWidget->hide(); QCoreApplication::processEvents(); - const auto databaseKey = buildDatabaseKey(); + const auto databaseKey = buildDatabaseKey(yubikey); if (!databaseKey) { setUserInteractionLock(false); return; @@ -430,7 +431,7 @@ void DatabaseOpenWidget::openDatabase() } } -QSharedPointer DatabaseOpenWidget::buildDatabaseKey() +QSharedPointer DatabaseOpenWidget::buildDatabaseKey(const QString& yubikey) { auto databaseKey = QSharedPointer::create(); @@ -490,6 +491,29 @@ QSharedPointer DatabaseOpenWidget::buildDatabaseKey() } #ifdef WITH_XC_YUBIKEY + if (!yubikey.isEmpty()) { + unsigned int serial = 0; + int slot; + + bool ok = false; + auto parts = yubikey.split(":"); + slot = parts[0].toInt(&ok); + + if (!ok || (slot != 1 && slot != 2)) { + return {}; + } + + if (parts.size() > 1) { + serial = parts[1].toUInt(&ok, 10); + if (!ok) { + return {}; + } + } + + auto crKey = QSharedPointer(new ChallengeResponseKey({serial, slot})); + databaseKey->addChallengeResponseKey(crKey); + } + auto lastChallengeResponse = config()->get(Config::LastChallengeResponse).toHash(); lastChallengeResponse.remove(m_filename); diff --git a/src/gui/DatabaseOpenWidget.h b/src/gui/DatabaseOpenWidget.h index d730634b3..5af3c7681 100644 --- a/src/gui/DatabaseOpenWidget.h +++ b/src/gui/DatabaseOpenWidget.h @@ -49,7 +49,7 @@ public: void load(const QString& filename); QString filename(); void clearForms(); - void enterKey(const QString& pw, const QString& keyFile); + void enterKey(const QString& pw, const QString& keyFile, const QString& yubikey = {}); QSharedPointer database(); bool unlockingDatabase(); void showMessage(const QString& text, MessageWidget::MessageType type, int autoHideTimeout); @@ -67,7 +67,7 @@ signals: protected: bool event(QEvent* event) override; void keyPressEvent(QKeyEvent* event) override; - QSharedPointer buildDatabaseKey(); + QSharedPointer buildDatabaseKey(const QString& yubikey = {}); void setUserInteractionLock(bool state); const QScopedPointer m_ui; @@ -76,7 +76,7 @@ protected: bool m_retryUnlockWithEmptyPassword = false; protected slots: - virtual void openDatabase(); + virtual void openDatabase(const QString& yubikey = {}); void reject(); private slots: diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 2bf18071d..e7fb0625d 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -156,7 +156,8 @@ void DatabaseTabWidget::openDatabase() void DatabaseTabWidget::addDatabaseTab(const QString& filePath, bool inBackground, const QString& password, - const QString& keyfile) + const QString& keyfile, + const QString& yubikey) { QString cleanFilePath = QDir::toNativeSeparators(filePath); QFileInfo fileInfo(cleanFilePath); @@ -173,7 +174,7 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath, Q_ASSERT(dbWidget); if (dbWidget && dbWidget->database()->canonicalFilePath().compare(canonicalFilePath, FILE_CASE_SENSITIVE) == 0) { - dbWidget->performUnlockDatabase(password, keyfile); + dbWidget->performUnlockDatabase(password, keyfile, yubikey); if (!inBackground) { // switch to existing tab if file is already open setCurrentIndex(indexOf(dbWidget)); @@ -184,7 +185,7 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath, auto* dbWidget = new DatabaseWidget(QSharedPointer::create(cleanFilePath), this); addDatabaseTab(dbWidget, inBackground); - dbWidget->performUnlockDatabase(password, keyfile); + dbWidget->performUnlockDatabase(password, keyfile, yubikey); updateLastDatabases(dbWidget->database()); } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index a5074a84c..467fd766d 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -53,7 +53,8 @@ public slots: void addDatabaseTab(const QString& filePath, bool inBackground = false, const QString& password = {}, - const QString& keyfile = {}); + const QString& keyfile = {}, + const QString& yubikey = {}); void addDatabaseTab(DatabaseWidget* dbWidget, bool inBackground = false); bool closeDatabaseTab(int index); bool closeDatabaseTab(DatabaseWidget* dbWidget); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 2afde49fe..f7d47ae0a 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -1720,7 +1720,7 @@ void DatabaseWidget::removePasskeyFromEntry() } #endif -void DatabaseWidget::performUnlockDatabase(const QString& password, const QString& keyfile) +void DatabaseWidget::performUnlockDatabase(const QString& password, const QString& keyfile, const QString& yubikey) { if (password.isEmpty() && keyfile.isEmpty()) { return; @@ -1728,7 +1728,7 @@ void DatabaseWidget::performUnlockDatabase(const QString& password, const QStrin if (!m_db->isInitialized() || isLocked()) { switchToOpenDatabase(); - m_databaseOpenWidget->enterKey(password, keyfile); + m_databaseOpenWidget->enterKey(password, keyfile, yubikey); } } diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index d624a7e61..c19c1652c 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -244,7 +244,7 @@ public slots: void switchToOpenDatabase(); void switchToOpenDatabase(const QString& filePath); void switchToOpenDatabase(const QString& filePath, const QString& password, const QString& keyFile); - void performUnlockDatabase(const QString& password, const QString& keyfile = {}); + void performUnlockDatabase(const QString& password, const QString& keyfile = {}, const QString& yubikey = {}); void emptyRecycleBin(); // Search related slots diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 25b96c5ae..81578fd13 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -887,9 +887,9 @@ void MainWindow::clearLastDatabases() } } -void MainWindow::openDatabase(const QString& filePath, const QString& password, const QString& keyfile) +void MainWindow::openDatabase(const QString& filePath, const QString& password, const QString& keyfile, const QString& yubikey) { - m_ui->tabWidget->addDatabaseTab(filePath, false, password, keyfile); + m_ui->tabWidget->addDatabaseTab(filePath, false, password, keyfile, yubikey); } void MainWindow::updateMenuActionState() diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 8effd06f4..4293c80c0 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -70,7 +70,7 @@ signals: void databaseUnlockDialogFinished(bool accepted, DatabaseWidget* dbWidget); public slots: - void openDatabase(const QString& filePath, const QString& password = {}, const QString& keyfile = {}); + void openDatabase(const QString& filePath, const QString& password = {}, const QString& keyfile = {}, const QString& yubikey = {}); void appExit(); bool isHardwareKeySupported(); bool refreshHardwareKeys(); diff --git a/src/main.cpp b/src/main.cpp index a08642b34..c75a6c08b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,6 +89,7 @@ int main(int argc, char** argv) "localconfig", QObject::tr("path to a custom local config file"), "localconfig"); QCommandLineOption lockOption("lock", QObject::tr("lock all open databases")); QCommandLineOption keyfileOption("keyfile", QObject::tr("key file of the database"), "keyfile"); + QCommandLineOption yubikeyOption("yubikey", QObject::tr("Yubikey slot and optional serial used to access the database (e.g., 1:7370001)."), "slot[:serial"); QCommandLineOption pwstdinOption("pw-stdin", QObject::tr("read password of the database from stdin")); QCommandLineOption allowScreenCaptureOption("allow-screencapture", QObject::tr("allow screenshots and app recording (Windows/macOS)")); @@ -101,6 +102,7 @@ int main(int argc, char** argv) parser.addOption(localConfigOption); parser.addOption(lockOption); parser.addOption(keyfileOption); + parser.addOption(yubikeyOption); parser.addOption(pwstdinOption); parser.addOption(debugInfoOption); parser.addOption(allowScreenCaptureOption); @@ -213,7 +215,7 @@ int main(int argc, char** argv) out << QObject::tr("Database password: ") << Qt::flush; password = Utils::getPassword(); } - mainWindow.openDatabase(filename, password, parser.value(keyfileOption)); + mainWindow.openDatabase(filename, password, parser.value(keyfileOption), parser.value(yubikeyOption)); } // start minimized if configured