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:
Laurent Erignoux 2020-07-25 12:09:36 +08:00 committed by Jonathan White
parent bbdfbe64da
commit f49f62d3be
6 changed files with 49 additions and 1 deletions

View File

@ -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.

View File

@ -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;

View File

@ -29,6 +29,7 @@ public:
static const QCommandLineOption AttributeOption;
static const QCommandLineOption TotpOption;
static const QCommandLineOption BestMatchOption;
};
#endif // KEEPASSXC_CLIP_H

View File

@ -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()

View File

@ -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;

Binary file not shown.