mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-02-22 15:39:57 -05:00
Add a best option to CLI command clip (#4489)
The best option copy the password from the best match if only one matching entry exists. Adding clip best option documentation Adding unit tests on the new clip --best option
This commit is contained in:
parent
bbdfbe64da
commit
f49f62d3be
@ -207,6 +207,11 @@ The same password generation options as documented for the generate command can
|
||||
Copies the current TOTP instead of the specified attribute to the clipboard.
|
||||
Will report an error if no TOTP is configured for the entry.
|
||||
|
||||
*-b*, *--best*::
|
||||
Try to find and copy to clipboard a unique entry matching the input (similar to *-locate*)
|
||||
If a unique matching entry is found it will be copied to the clipboard.
|
||||
If multiple entries are found they will be listed to refine the search. (no clip performed)
|
||||
|
||||
=== Create options
|
||||
*-k*, *--set-key-file* <__path__>::
|
||||
Set the key file for the database.
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Global.h"
|
||||
#include "core/Group.h"
|
||||
|
||||
const QCommandLineOption Clip::AttributeOption = QCommandLineOption(
|
||||
@ -39,12 +40,18 @@ const QCommandLineOption Clip::TotpOption =
|
||||
<< "totp",
|
||||
QObject::tr("Copy the current TOTP to the clipboard (equivalent to \"-a totp\")."));
|
||||
|
||||
const QCommandLineOption Clip::BestMatchOption = QCommandLineOption(
|
||||
QStringList() << "b"
|
||||
<< "best-match",
|
||||
QObject::tr("Try to find the unique entry matching, will fail and display the list of matches otherwise."));
|
||||
|
||||
Clip::Clip()
|
||||
{
|
||||
name = QString("clip");
|
||||
description = QObject::tr("Copy an entry's attribute to the clipboard.");
|
||||
options.append(Clip::AttributeOption);
|
||||
options.append(Clip::TotpOption);
|
||||
options.append(Clip::BestMatchOption);
|
||||
positionalArguments.append(
|
||||
{QString("entry"), QObject::tr("Path of the entry to clip.", "clip = copy to clipboard"), QString("")});
|
||||
optionalArguments.append(
|
||||
@ -57,12 +64,31 @@ int Clip::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<
|
||||
auto& err = Utils::STDERR;
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
const QString& entryPath = args.at(1);
|
||||
QString bestEntryPath;
|
||||
|
||||
QString timeout;
|
||||
if (args.size() == 3) {
|
||||
timeout = args.at(2);
|
||||
}
|
||||
|
||||
if (parser->isSet(Clip::BestMatchOption)) {
|
||||
QStringList results = database->rootGroup()->locate(args.at(1));
|
||||
if (results.count() > 1) {
|
||||
err << QObject::tr("Multiple entries matching:") << endl;
|
||||
for (const QString& result : asConst(results)) {
|
||||
err << result << endl;
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
bestEntryPath = (results.isEmpty()) ? args.at(1) : results[0];
|
||||
out << QObject::tr("Matching \"%1\" entry used.").arg(bestEntryPath) << endl;
|
||||
}
|
||||
} else {
|
||||
bestEntryPath = args.at(1);
|
||||
}
|
||||
|
||||
const QString& entryPath = bestEntryPath;
|
||||
|
||||
int timeoutSeconds = 0;
|
||||
if (!timeout.isEmpty() && timeout.toInt() <= 0) {
|
||||
err << QObject::tr("Invalid timeout value %1.").arg(timeout) << endl;
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
|
||||
static const QCommandLineOption AttributeOption;
|
||||
static const QCommandLineOption TotpOption;
|
||||
static const QCommandLineOption BestMatchOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_CLIP_H
|
||||
|
@ -86,6 +86,9 @@ void TestCli::init()
|
||||
m_dbFile2.reset(new TemporaryFile());
|
||||
m_dbFile2->copyFromFile(file.arg("NewDatabase2.kdbx"));
|
||||
|
||||
m_dbFileMulti.reset(new TemporaryFile());
|
||||
m_dbFileMulti->copyFromFile(file.arg("NewDatabaseMulti.kdbx"));
|
||||
|
||||
m_xmlFile.reset(new TemporaryFile());
|
||||
m_xmlFile->copyFromFile(file.arg("NewDatabase.xml"));
|
||||
|
||||
@ -115,6 +118,7 @@ void TestCli::cleanup()
|
||||
{
|
||||
m_dbFile.reset();
|
||||
m_dbFile2.reset();
|
||||
m_dbFileMulti.reset();
|
||||
m_keyFileProtectedDbFile.reset();
|
||||
m_keyFileProtectedNoPasswordDbFile.reset();
|
||||
m_yubiKeyProtectedDbFile.reset();
|
||||
@ -504,6 +508,17 @@ void TestCli::testClip()
|
||||
setInput("a");
|
||||
execCmd(clipCmd, {"clip", m_dbFile2->fileName(), "--attribute", "Username", "--totp", "/Sample Entry"});
|
||||
QVERIFY(m_stderr->readAll().contains("ERROR: Please specify one of --attribute or --totp, not both.\n"));
|
||||
|
||||
// Best option
|
||||
setInput("a");
|
||||
execCmd(clipCmd, {"clip", m_dbFileMulti->fileName(), "Multi", "-b"});
|
||||
QByteArray errorChoices = m_stderr->readAll();
|
||||
QVERIFY(errorChoices.contains("Multi Entry 1"));
|
||||
QVERIFY(errorChoices.contains("Multi Entry 2"));
|
||||
|
||||
setInput("a");
|
||||
execCmd(clipCmd, {"clip", m_dbFileMulti->fileName(), "Entry 2", "-b"});
|
||||
QTRY_COMPARE(clipboard->text(), QString("Password2"));
|
||||
}
|
||||
|
||||
void TestCli::testCreate()
|
||||
|
@ -83,6 +83,7 @@ private slots:
|
||||
private:
|
||||
QScopedPointer<TemporaryFile> m_dbFile;
|
||||
QScopedPointer<TemporaryFile> m_dbFile2;
|
||||
QScopedPointer<TemporaryFile> m_dbFileMulti;
|
||||
QScopedPointer<TemporaryFile> m_xmlFile;
|
||||
QScopedPointer<TemporaryFile> m_keyFileProtectedDbFile;
|
||||
QScopedPointer<TemporaryFile> m_keyFileProtectedNoPasswordDbFile;
|
||||
|
BIN
tests/data/NewDatabaseMulti.kdbx
Normal file
BIN
tests/data/NewDatabaseMulti.kdbx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user