CLI: Cleanup create options (#4313)

* Add ability to create database with an empty password
* Add password repeat check
* Standardize process between `db-create` and `import` commands
* Improve db-create tests with new password repeat

Co-authored-by: Jonathan White <support@dmapps.us>
This commit is contained in:
louib 2020-03-18 21:51:36 -04:00 committed by GitHub
parent b045160e4f
commit e6c2c7ed93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 171 additions and 54 deletions

View file

@ -566,73 +566,133 @@ void TestCli::testCreate()
QVERIFY(createCmd.getDescriptionLine().contains(createCmd.name));
QScopedPointer<QTemporaryDir> testDir(new QTemporaryDir());
QString dbFilename;
QString databaseFilename = testDir->path() + "/testCreate1.kdbx";
// Password
// Testing password option, password mismatch
dbFilename = testDir->path() + "/testCreate_pw.kdbx";
Utils::Test::setNextPassword("a");
createCmd.execute({"db-create", databaseFilename});
Utils::Test::setNextPassword("b");
createCmd.execute({"db-create", dbFilename, "-p"});
m_stderrFile->reset();
m_stdoutFile->reset();
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Error: Passwords do not match.\n"));
QCOMPARE(m_stderrFile->readLine(), QByteArray("Failed to set database password.\n"));
// Testing password option
Utils::Test::setNextPassword("a", true);
qint64 pos = m_stdoutFile->pos();
qint64 errPos = m_stderrFile->pos();
createCmd.execute({"db-create", dbFilename, "-p"});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
auto db = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename, true, "", "", Utils::DEVNULL));
auto db = Utils::unlockDatabase(dbFilename, true, "", "", Utils::DEVNULL);
QVERIFY(db);
// Testing with empty password (deny it)
dbFilename = testDir->path() + "/testCreate_blankpw.kdbx";
Utils::Test::setNextPassword("");
m_stdinFile->reset();
m_stdinFile->write("n\n");
m_stdinFile->reset();
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"db-create", dbFilename, "-p"});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QVERIFY(m_stdoutFile->readLine().contains("empty password"));
QCOMPARE(m_stderrFile->readLine(), QByteArray("Failed to set database password.\n"));
// Testing with empty password (accept it)
Utils::Test::setNextPassword("");
m_stdinFile->reset();
m_stdinFile->write("y\n");
m_stdinFile->reset();
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"db-create", dbFilename, "-p"});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QVERIFY(m_stdoutFile->readLine().contains("empty password"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("");
db = Utils::unlockDatabase(dbFilename, true, "", "", Utils::DEVNULL);
QVERIFY(db);
// Should refuse to create the database if it already exists.
qint64 pos = m_stdoutFile->pos();
qint64 errPos = m_stderrFile->pos();
createCmd.execute({"db-create", databaseFilename});
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"db-create", "-p", dbFilename});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
// Output should be empty when there is an error.
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
QString errorMessage = QString("File " + databaseFilename + " already exists.\n");
QString errorMessage = QString("File " + dbFilename + " already exists.\n");
QCOMPARE(m_stderrFile->readAll(), errorMessage.toUtf8());
// Should refuse to create without any key provided.
dbFilename = testDir->path() + "/testCreate_key.kdbx";
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"db-create", dbFilename});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
QCOMPARE(m_stderrFile->readLine(), QByteArray("No key is set. Aborting database creation.\n"));
// Testing with keyfile creation
QString databaseFilename2 = testDir->path() + "/testCreate2.kdbx";
dbFilename = testDir->path() + "/testCreate_key2.kdbx";
QString keyfilePath = testDir->path() + "/keyfile.txt";
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
Utils::Test::setNextPassword("a");
createCmd.execute({"db-create", databaseFilename2, "-k", keyfilePath});
Utils::Test::setNextPassword("a", true);
createCmd.execute({"db-create", dbFilename, "-p", "-k", keyfilePath});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
auto db2 =
QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename2, true, keyfilePath, "", Utils::DEVNULL));
QVERIFY(db2);
db = Utils::unlockDatabase(dbFilename, true, keyfilePath, "", Utils::DEVNULL);
QVERIFY(db);
// Testing with existing keyfile
QString databaseFilename3 = testDir->path() + "/testCreate3.kdbx";
dbFilename = testDir->path() + "/testCreate_key3.kdbx";
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
Utils::Test::setNextPassword("a");
createCmd.execute({"db-create", databaseFilename3, "-k", keyfilePath});
Utils::Test::setNextPassword("a", true);
createCmd.execute({"db-create", dbFilename, "-p", "-k", keyfilePath});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully created new database.\n"));
Utils::Test::setNextPassword("a");
auto db3 =
QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename3, true, keyfilePath, "", Utils::DEVNULL));
QVERIFY(db3);
db = Utils::unlockDatabase(dbFilename, true, keyfilePath, "", Utils::DEVNULL);
QVERIFY(db);
// Invalid decryption time (format).
QString databaseFilename4 = testDir->path() + "/testCreate4.kdbx";
dbFilename = testDir->path() + "/testCreate_time.kdbx";
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"create", databaseFilename4, "-t", "NAN"});
createCmd.execute({"db-create", dbFilename, "-p", "-t", "NAN"});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
@ -642,7 +702,7 @@ void TestCli::testCreate()
// Invalid decryption time (range).
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
createCmd.execute({"create", databaseFilename4, "-t", "10"});
createCmd.execute({"db-create", dbFilename, "-p", "-t", "10"});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
@ -653,9 +713,9 @@ void TestCli::testCreate()
// Custom encryption time
pos = m_stdoutFile->pos();
errPos = m_stderrFile->pos();
Utils::Test::setNextPassword("a");
Utils::Test::setNextPassword("a", true);
int epochBefore = QDateTime::currentMSecsSinceEpoch();
createCmd.execute({"create", databaseFilename4, "-t", QString::number(encryptionTime)});
createCmd.execute({"db-create", dbFilename, "-p", "-t", QString::number(encryptionTime)});
// Removing 100ms to make sure we account for changes in computation time.
QVERIFY(QDateTime::currentMSecsSinceEpoch() > (epochBefore + encryptionTime - 100));
m_stdoutFile->seek(pos);
@ -663,12 +723,13 @@ void TestCli::testCreate()
QCOMPARE(m_stderrFile->readAll(), QByteArray(""));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Benchmarking key derivation function for 500ms delay.\n"));
QVERIFY(m_stdoutFile->readLine().contains(QByteArray("rounds for key derivation function.\n")));
Utils::Test::setNextPassword("a");
auto db4 = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilename4, true, "", "", Utils::DEVNULL));
QVERIFY(db4);
db = Utils::unlockDatabase(dbFilename, true, "", "", Utils::DEVNULL);
QVERIFY(db);
}
void TestCli::testInfo()
@ -1105,13 +1166,14 @@ void TestCli::testImport()
QScopedPointer<QTemporaryDir> testDir(new QTemporaryDir());
QString databaseFilename = testDir->path() + "testImport1.kdbx";
Utils::Test::setNextPassword("a");
Utils::Test::setNextPassword("a", true);
importCmd.execute({"import", m_xmlFile->fileName(), databaseFilename});
m_stderrFile->reset();
m_stdoutFile->reset();
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully imported database.\n"));
Utils::Test::setNextPassword("a");
@ -1137,11 +1199,13 @@ void TestCli::testImport()
QString databaseFilenameQuiet = testDirQuiet->path() + "testImport2.kdbx";
pos = m_stdoutFile->pos();
Utils::Test::setNextPassword("a");
Utils::Test::setNextPassword("a", true);
importCmd.execute({"import", "-q", m_xmlFile->fileName(), databaseFilenameQuiet});
m_stdoutFile->seek(pos);
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Enter password to encrypt database (optional): \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Repeat password: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray());
Utils::Test::setNextPassword("a");
auto dbQuiet = QSharedPointer<Database>(Utils::unlockDatabase(databaseFilenameQuiet, true, "", "", Utils::DEVNULL));
@ -1544,11 +1608,11 @@ void TestCli::testMergeWithKeys()
qint64 pos = m_stdoutFile->pos();
Utils::Test::setNextPassword("a");
createCmd.execute({"db-create", sourceDatabaseFilename, "-k", sourceKeyfilePath});
Utils::Test::setNextPassword("a", true);
createCmd.execute({"db-create", sourceDatabaseFilename, "-p", "-k", sourceKeyfilePath});
Utils::Test::setNextPassword("b");
createCmd.execute({"db-create", targetDatabaseFilename, "-k", targetKeyfilePath});
Utils::Test::setNextPassword("b", true);
createCmd.execute({"db-create", targetDatabaseFilename, "-p", "-k", targetKeyfilePath});
Utils::Test::setNextPassword("a");
auto sourceDatabase = QSharedPointer<Database>(