mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-08-09 23:12:23 -04:00
CLI: Add Yubikey unlock support
This commit is contained in:
parent
77fcde875e
commit
964478e78f
19 changed files with 816 additions and 529 deletions
|
@ -52,6 +52,12 @@ const QCommandLineOption Command::KeyFileOption = QCommandLineOption(QStringList
|
|||
const QCommandLineOption Command::NoPasswordOption =
|
||||
QCommandLineOption(QStringList() << "no-password", QObject::tr("Deactivate password key for the database."));
|
||||
|
||||
const QCommandLineOption Command::YubiKeyOption =
|
||||
QCommandLineOption(QStringList() << "y"
|
||||
<< "yubikey",
|
||||
QObject::tr("Yubikey slot used to encrypt the database."),
|
||||
QObject::tr("slot"));
|
||||
|
||||
QMap<QString, Command*> commands;
|
||||
|
||||
Command::Command()
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
static const QCommandLineOption QuietOption;
|
||||
static const QCommandLineOption KeyFileOption;
|
||||
static const QCommandLineOption NoPasswordOption;
|
||||
static const QCommandLineOption YubiKeyOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_COMMAND_H
|
||||
|
|
|
@ -24,6 +24,9 @@ DatabaseCommand::DatabaseCommand()
|
|||
positionalArguments.append({QString("database"), QObject::tr("Path of the database."), QString("")});
|
||||
options.append(Command::KeyFileOption);
|
||||
options.append(Command::NoPasswordOption);
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
options.append(Command::YubiKeyOption);
|
||||
#endif
|
||||
}
|
||||
|
||||
int DatabaseCommand::execute(const QStringList& arguments)
|
||||
|
@ -37,6 +40,7 @@ int DatabaseCommand::execute(const QStringList& arguments)
|
|||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser->isSet(Command::NoPasswordOption),
|
||||
parser->value(Command::KeyFileOption),
|
||||
parser->value(Command::YubiKeyOption),
|
||||
parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
|
|
|
@ -43,6 +43,9 @@ const QCommandLineOption Merge::DryRunOption =
|
|||
QCommandLineOption(QStringList() << "dry-run",
|
||||
QObject::tr("Only print the changes detected by the merge operation."));
|
||||
|
||||
const QCommandLineOption Merge::YubiKeyFromOption(QStringList() << "yubikey-from",
|
||||
QObject::tr("Yubikey slot for the second database."),
|
||||
QObject::tr("slot"));
|
||||
Merge::Merge()
|
||||
{
|
||||
name = QString("merge");
|
||||
|
@ -51,6 +54,9 @@ Merge::Merge()
|
|||
options.append(Merge::KeyFileFromOption);
|
||||
options.append(Merge::NoPasswordFromOption);
|
||||
options.append(Merge::DryRunOption);
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
options.append(Merge::YubiKeyFromOption);
|
||||
#endif
|
||||
positionalArguments.append({QString("database2"), QObject::tr("Path of the database to merge from."), QString("")});
|
||||
}
|
||||
|
||||
|
@ -70,6 +76,7 @@ int Merge::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer
|
|||
db2 = Utils::unlockDatabase(fromDatabasePath,
|
||||
!parser->isSet(Merge::NoPasswordFromOption),
|
||||
parser->value(Merge::KeyFileFromOption),
|
||||
parser->value(Merge::YubiKeyFromOption),
|
||||
parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db2) {
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
static const QCommandLineOption SameCredentialsOption;
|
||||
static const QCommandLineOption KeyFileFromOption;
|
||||
static const QCommandLineOption NoPasswordFromOption;
|
||||
static const QCommandLineOption YubiKeyFromOption;
|
||||
static const QCommandLineOption DryRunOption;
|
||||
};
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ namespace Utils
|
|||
QSharedPointer<Database> unlockDatabase(const QString& databaseFilename,
|
||||
const bool isPasswordProtected,
|
||||
const QString& keyFilename,
|
||||
const QString& yubiKeySlot,
|
||||
FILE* outputDescriptor,
|
||||
FILE* errorDescriptor)
|
||||
{
|
||||
|
@ -153,6 +154,31 @@ namespace Utils
|
|||
compositeKey->addKey(fileKey);
|
||||
}
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
if (!yubiKeySlot.isEmpty()) {
|
||||
bool ok = false;
|
||||
int slot = yubiKeySlot.toInt(&ok, 10);
|
||||
if (!ok || (slot != 1 && slot != 2)) {
|
||||
err << QObject::tr("Invalid YubiKey slot %1").arg(yubiKeySlot) << endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
QString errorMessage;
|
||||
bool blocking = YubiKey::instance()->checkSlotIsBlocking(slot, errorMessage);
|
||||
if (!errorMessage.isEmpty()) {
|
||||
err << errorMessage << endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto key = QSharedPointer<YkChallengeResponseKeyCLI>(new YkChallengeResponseKeyCLI(
|
||||
slot,
|
||||
blocking,
|
||||
QObject::tr("Please touch the button on your YubiKey to unlock %1").arg(databaseFilename),
|
||||
outputDescriptor));
|
||||
compositeKey->addChallengeResponseKey(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
auto db = QSharedPointer<Database>::create();
|
||||
QString error;
|
||||
if (db->open(databaseFilename, compositeKey, &error, false)) {
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
#include "keys/PasswordKey.h"
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifdef WITH_XC_YUBIKEY
|
||||
#include "keys/YkChallengeResponseKey.h"
|
||||
#include "keys/YkChallengeResponseKeyCLI.h"
|
||||
#include "keys/drivers/YubiKey.h"
|
||||
#endif
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
extern FILE* STDOUT;
|
||||
|
@ -38,6 +44,7 @@ namespace Utils
|
|||
QSharedPointer<Database> unlockDatabase(const QString& databaseFilename,
|
||||
const bool isPasswordProtected = true,
|
||||
const QString& keyFilename = {},
|
||||
const QString& yubiKeySlot = {},
|
||||
FILE* outputDescriptor = STDOUT,
|
||||
FILE* errorDescriptor = STDERR);
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ Specifies a path to a key file for unlocking the database. In a merge operation
|
|||
.IP "--no-password"
|
||||
Deactivate password key for the database.
|
||||
|
||||
.IP "-y, --yubikey <slot>"
|
||||
Specifies a yubikey slot for unlocking the database. In a merge operation this option is used to specify the yubikey slot for the first database.
|
||||
|
||||
.IP "-q, --quiet <path>"
|
||||
Silence password prompt and other secondary outputs.
|
||||
|
||||
|
@ -91,6 +94,9 @@ Path of the key file for the second database.
|
|||
.IP "--no-password-from"
|
||||
Deactivate password key for the database to merge from.
|
||||
|
||||
.IP "--yubikey-from <slot>"
|
||||
Yubikey slot for the second database.
|
||||
|
||||
.IP "-s, --same-credentials"
|
||||
Use the same credentials for unlocking both database.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue