mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-08-03 12:06:25 -04:00
✨✨ CLI Command cleanup ✨✨
This PR cleans up the `Command` classes in the CLI, introducing a `DatabaseCommand` class for the commands operating on a database, and a `getCommandLineParser` command to centralize the arguments parsing and validation. The opening of the database based on the CLI arguments and options is now centralized in `DatabaseCommand.execute`, making it easy to add new database opening features (like YubiKey support for the CLI). Also a couple of bugs fixed: * `Create` was still using `stdout` for some error messages. * `Diceware` and `Generate` were not validating that the word count was an integer. * `Diceware` was also using `stdout` for some error messages.
This commit is contained in:
parent
3cf171cbf5
commit
04360ed552
31 changed files with 591 additions and 637 deletions
|
@ -197,6 +197,7 @@ void TestCli::testAdd()
|
|||
m_stderrFile->reset();
|
||||
m_stdoutFile->reset();
|
||||
m_stdoutFile->readLine(); // skip password prompt
|
||||
QCOMPARE(m_stderrFile->readAll(), QByteArray(""));
|
||||
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Successfully added entry newuser-entry.\n"));
|
||||
|
||||
auto db = readTestDatabase();
|
||||
|
@ -296,7 +297,9 @@ void TestCli::testClip()
|
|||
// Password with timeout
|
||||
Utils::Test::setNextPassword("a");
|
||||
// clang-format off
|
||||
QFuture<void> future = QtConcurrent::run(&clipCmd, &Clip::execute, QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1"});
|
||||
QFuture<void> future = QtConcurrent::run(&clipCmd,
|
||||
static_cast<int(Clip::*)(const QStringList&)>(&DatabaseCommand::execute),
|
||||
QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1"});
|
||||
// clang-format on
|
||||
|
||||
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString("Password"), 500);
|
||||
|
@ -306,8 +309,9 @@ void TestCli::testClip()
|
|||
|
||||
// TOTP with timeout
|
||||
Utils::Test::setNextPassword("a");
|
||||
future = QtConcurrent::run(
|
||||
&clipCmd, &Clip::execute, QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1", "-t"});
|
||||
future = QtConcurrent::run(&clipCmd,
|
||||
static_cast<int (Clip::*)(const QStringList&)>(&DatabaseCommand::execute),
|
||||
QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1", "-t"});
|
||||
|
||||
QTRY_VERIFY_WITH_TIMEOUT(isTOTP(clipboard->text()), 500);
|
||||
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 1500);
|
||||
|
@ -316,6 +320,18 @@ void TestCli::testClip()
|
|||
|
||||
qint64 posErr = m_stderrFile->pos();
|
||||
Utils::Test::setNextPassword("a");
|
||||
clipCmd.execute({"clip", m_dbFile->fileName(), "--totp", "/Sample Entry", "0"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readAll(), QByteArray("Invalid timeout value 0.\n"));
|
||||
|
||||
posErr = m_stderrFile->pos();
|
||||
Utils::Test::setNextPassword("a");
|
||||
clipCmd.execute({"clip", m_dbFile->fileName(), "--totp", "/Sample Entry", "bleuh"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readAll(), QByteArray("Invalid timeout value bleuh.\n"));
|
||||
|
||||
posErr = m_stderrFile->pos();
|
||||
Utils::Test::setNextPassword("a");
|
||||
clipCmd.execute({"clip", m_dbFile2->fileName(), "--totp", "/Sample Entry"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readAll(), QByteArray("Entry with path /Sample Entry has no TOTP set up.\n"));
|
||||
|
@ -414,6 +430,18 @@ void TestCli::testDiceware()
|
|||
passphrase = m_stdoutFile->readLine();
|
||||
QCOMPARE(passphrase.split(" ").size(), 10);
|
||||
|
||||
// Testing with invalid word count
|
||||
auto posErr = m_stderrFile->pos();
|
||||
dicewareCmd.execute({"diceware", "-W", "-10"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("Invalid word count -10\n"));
|
||||
|
||||
// Testing with invalid word count format
|
||||
posErr = m_stderrFile->pos();
|
||||
dicewareCmd.execute({"diceware", "-W", "bleuh"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("Invalid word count bleuh\n"));
|
||||
|
||||
TemporaryFile wordFile;
|
||||
wordFile.open();
|
||||
for (int i = 0; i < 4500; ++i) {
|
||||
|
@ -431,6 +459,18 @@ void TestCli::testDiceware()
|
|||
for (const auto& word : words) {
|
||||
QVERIFY2(regex.match(word).hasMatch(), qPrintable("Word " + word + " was not on the word list"));
|
||||
}
|
||||
|
||||
TemporaryFile smallWordFile;
|
||||
smallWordFile.open();
|
||||
for (int i = 0; i < 50; ++i) {
|
||||
smallWordFile.write(QString("word" + QString::number(i) + "\n").toLatin1());
|
||||
}
|
||||
smallWordFile.close();
|
||||
|
||||
posErr = m_stderrFile->pos();
|
||||
dicewareCmd.execute({"diceware", "-W", "11", "-w", smallWordFile.fileName()});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("The word list is too small (< 1000 items)\n"));
|
||||
}
|
||||
|
||||
void TestCli::testEdit()
|
||||
|
@ -679,6 +719,23 @@ void TestCli::testGenerate()
|
|||
QVERIFY2(regex.match(password).hasMatch(),
|
||||
qPrintable("Password " + password + " does not match pattern " + pattern));
|
||||
}
|
||||
|
||||
// Testing with invalid password length
|
||||
auto posErr = m_stderrFile->pos();
|
||||
generateCmd.execute({"generate", "-L", "-10"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("Invalid password length -10\n"));
|
||||
|
||||
posErr = m_stderrFile->pos();
|
||||
generateCmd.execute({"generate", "-L", "0"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("Invalid password length 0\n"));
|
||||
|
||||
// Testing with invalid word count format
|
||||
posErr = m_stderrFile->pos();
|
||||
generateCmd.execute({"generate", "-L", "bleuh"});
|
||||
m_stderrFile->seek(posErr);
|
||||
QCOMPARE(m_stderrFile->readLine(), QByteArray("Invalid password length bleuh\n"));
|
||||
}
|
||||
|
||||
void TestCli::testKeyFileOption()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue