Skip to content

Commit

Permalink
Adding db-show CLI command.
Browse files Browse the repository at this point in the history
This adds a basic db-show CLI command, to display
the information related to a database.
  • Loading branch information
louib authored and louib committed Jan 24, 2020
1 parent b6ff613 commit d86068b
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 3 deletions.
3 changes: 3 additions & 0 deletions share/docs/man/keepassxc-cli.1
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ Removes a group from a database. If the database has a recycle bin, the group wi
.IP "show [options] <database> <entry>"
Shows the title, username, password, URL and notes of a database entry. Can also show the current TOTP. Regarding the occurrence of multiple entries with the same name in different groups, everything stated in the \fIclip\fP command section also applies here.

.IP "db-show [options] <database>"
Show a database's information.

.SH OPTIONS

.SS "General options"
Expand Down
3 changes: 2 additions & 1 deletion src/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ set(cli_SOURCES
Open.cpp
Remove.cpp
RemoveGroup.cpp
Show.cpp)
Show.cpp
ShowDatabase.cpp)

add_library(cli STATIC ${cli_SOURCES})
target_link_libraries(cli Qt5::Core Qt5::Widgets)
Expand Down
2 changes: 2 additions & 0 deletions src/cli/Command.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "Remove.h"
#include "RemoveGroup.h"
#include "Show.h"
#include "ShowDatabase.h"
#include "TextStream.h"
#include "Utils.h"

Expand Down Expand Up @@ -175,6 +176,7 @@ namespace Commands
s_commands.insert(QStringLiteral("rm"), QSharedPointer<Command>(new Remove()));
s_commands.insert(QStringLiteral("rmdir"), QSharedPointer<Command>(new RemoveGroup()));
s_commands.insert(QStringLiteral("show"), QSharedPointer<Command>(new Show()));
s_commands.insert(QStringLiteral("db-show"), QSharedPointer<Command>(new ShowDatabase()));

if (interactive) {
s_commands.insert(QStringLiteral("exit"), QSharedPointer<Command>(new Exit("exit")));
Expand Down
48 changes: 48 additions & 0 deletions src/cli/ShowDatabase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <stdio.h>

#include "ShowDatabase.h"

#include "core/Database.h"
#include "core/Metadata.h"

#include "Utils.h"

ShowDatabase::ShowDatabase()
{
name = QString("db-show");
description = QObject::tr("Show a database's information.");
}

int ShowDatabase::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser>)
{
TextStream out(Utils::STDOUT, QIODevice::WriteOnly);

out << QObject::tr("UUID: ") << database->uuid().toString() << endl;
out << QObject::tr("Name: ") << database->metadata()->name() << endl;
out << QObject::tr("Description: ") << database->metadata()->description() << endl;
out << QObject::tr("Cipher: ") << SymmetricCipher::cipherToString(database->cipher()) << endl;
out << QObject::tr("KDF: ") << database->kdf()->toString() << endl;
if (database->metadata()->recycleBinEnabled()) {
out << QObject::tr("Recycle bin is enabled.") << endl;
} else {
out << QObject::tr("Recycle bin is not enabled.") << endl;
}
return EXIT_SUCCESS;
}
31 changes: 31 additions & 0 deletions src/cli/ShowDatabase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KEEPASSXC_SHOWDATABASE_H
#define KEEPASSXC_SHOWDATABASE_H

#include "DatabaseCommand.h"

class ShowDatabase : public DatabaseCommand
{
public:
ShowDatabase();

int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
};

#endif // KEEPASSXC_SHOWDATABASE_H
14 changes: 14 additions & 0 deletions src/crypto/SymmetricCipher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,20 @@ SymmetricCipher::Algorithm SymmetricCipher::cipherToAlgorithm(const QUuid& ciphe
return InvalidAlgorithm;
}

QString SymmetricCipher::cipherToString(const QUuid& cipher)
{
if (cipher == KeePass2::CIPHER_AES256) {
return QString("AES 256-bit");
} else if (cipher == KeePass2::CIPHER_CHACHA20) {
return QString("Chacha20");
} else if (cipher == KeePass2::CIPHER_TWOFISH) {
return QString("Twofish 256-bit");
}

qWarning("SymmetricCipher::cipherToString: invalid UUID %s", cipher.toString().toLatin1().data());
return QString();
}

QUuid SymmetricCipher::algorithmToCipher(Algorithm algo)
{
switch (algo) {
Expand Down
1 change: 1 addition & 0 deletions src/crypto/SymmetricCipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class SymmetricCipher
Algorithm algorithm() const;

static Algorithm cipherToAlgorithm(const QUuid& cipher);
static QString cipherToString(const QUuid& cipher);
static QUuid algorithmToCipher(Algorithm algo);
static int algorithmIvSize(Algorithm algo);
static Mode algorithmMode(Algorithm algo);
Expand Down
5 changes: 5 additions & 0 deletions src/crypto/kdf/AesKdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,8 @@ int AesKdf::benchmarkImpl(int msec) const

return static_cast<int>(rounds * (static_cast<float>(msec) / timer.elapsed()));
}

QString AesKdf::toString() const
{
return QObject::tr("AES (%1 rounds)").arg(QString::number(rounds()));
}
1 change: 1 addition & 0 deletions src/crypto/kdf/AesKdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class AesKdf : public Kdf
QVariantMap writeParameters() override;
bool transform(const QByteArray& raw, QByteArray& result) const override;
QSharedPointer<Kdf> clone() const override;
QString toString() const override;

protected:
int benchmarkImpl(int msec) const override;
Expand Down
5 changes: 5 additions & 0 deletions src/crypto/kdf/Argon2Kdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,8 @@ int Argon2Kdf::benchmarkImpl(int msec) const

return 1;
}

QString Argon2Kdf::toString() const
{
return QObject::tr("Argon2 (%1 rounds, %2 KB)").arg(QString::number(rounds()), QString::number(memory()));
}
1 change: 1 addition & 0 deletions src/crypto/kdf/Argon2Kdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class Argon2Kdf : public Kdf
bool setMemory(quint64 kibibytes);
quint32 parallelism() const;
bool setParallelism(quint32 threads);
QString toString() const override;

protected:
int benchmarkImpl(int msec) const override;
Expand Down
2 changes: 2 additions & 0 deletions src/crypto/kdf/Kdf.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class Kdf
virtual bool transform(const QByteArray& raw, QByteArray& result) const = 0;
virtual QSharedPointer<Kdf> clone() const = 0;

virtual QString toString() const = 0;

int benchmark(int msec) const;

protected:
Expand Down
42 changes: 40 additions & 2 deletions tests/TestCli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
#include "cli/Remove.h"
#include "cli/RemoveGroup.h"
#include "cli/Show.h"
#include "cli/ShowDatabase.h"
#include "cli/Utils.h"

#include <QClipboard>
Expand Down Expand Up @@ -190,6 +191,7 @@ void TestCli::testBatchCommands()
Commands::setupCommands(false);
QVERIFY(Commands::getCommand("add"));
QVERIFY(Commands::getCommand("analyze"));
QVERIFY(Commands::getCommand("db-show"));
QVERIFY(Commands::getCommand("clip"));
QVERIFY(Commands::getCommand("close"));
QVERIFY(Commands::getCommand("create"));
Expand All @@ -210,14 +212,15 @@ void TestCli::testBatchCommands()
QVERIFY(Commands::getCommand("rmdir"));
QVERIFY(Commands::getCommand("show"));
QVERIFY(!Commands::getCommand("doesnotexist"));
QCOMPARE(Commands::getCommands().size(), 21);
QCOMPARE(Commands::getCommands().size(), 22);
}

void TestCli::testInteractiveCommands()
{
Commands::setupCommands(true);
QVERIFY(Commands::getCommand("add"));
QVERIFY(Commands::getCommand("analyze"));
QVERIFY(Commands::getCommand("db-show"));
QVERIFY(Commands::getCommand("clip"));
QVERIFY(Commands::getCommand("close"));
QVERIFY(Commands::getCommand("create"));
Expand All @@ -238,7 +241,7 @@ void TestCli::testInteractiveCommands()
QVERIFY(Commands::getCommand("rmdir"));
QVERIFY(Commands::getCommand("show"));
QVERIFY(!Commands::getCommand("doesnotexist"));
QCOMPARE(Commands::getCommands().size(), 21);
QCOMPARE(Commands::getCommands().size(), 22);
}

void TestCli::testAdd()
Expand Down Expand Up @@ -607,6 +610,41 @@ void TestCli::testCreate()
QVERIFY(db3);
}

void TestCli::testShowDatabase()
{
ShowDatabase showDatabaseCmd;
QVERIFY(!showDatabaseCmd.name.isEmpty());
QVERIFY(showDatabaseCmd.getDescriptionLine().contains(showDatabaseCmd.name));

Utils::Test::setNextPassword("a");
showDatabaseCmd.execute({"db-show", m_dbFile->fileName()});
m_stdoutFile->reset();
m_stderrFile->reset();
m_stdoutFile->readLine(); // skip prompt line
QCOMPARE(m_stderrFile->readAll(), QByteArray(""));
QVERIFY(m_stdoutFile->readLine().contains(QByteArray("UUID: ")));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Name: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Description: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Cipher: AES 256-bit\n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("KDF: AES (6000 rounds)\n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Recycle bin is enabled.\n"));

// Test with quiet option.
qint64 pos = m_stdoutFile->pos();
qint64 errPos = m_stderrFile->pos();
Utils::Test::setNextPassword("a");
showDatabaseCmd.execute({"db-show", "-q", m_dbFile->fileName()});
m_stdoutFile->seek(pos);
m_stderrFile->seek(errPos);
QCOMPARE(m_stderrFile->readAll(), QByteArray(""));
QVERIFY(m_stdoutFile->readLine().contains(QByteArray("UUID: ")));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Name: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Description: \n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Cipher: AES 256-bit\n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("KDF: AES (6000 rounds)\n"));
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Recycle bin is enabled.\n"));
}

void TestCli::testDiceware()
{
Diceware dicewareCmd;
Expand Down
1 change: 1 addition & 0 deletions tests/TestCli.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ private slots:
void testRemoveGroup();
void testRemoveQuiet();
void testShow();
void testShowDatabase();
void testInvalidDbFiles();
void testYubiKeyOption();

Expand Down

0 comments on commit d86068b

Please sign in to comment.