mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-06-06 22:19:00 -04:00
Adding --quiet option to the CLI. (#2507)
This commit is contained in:
parent
4e49de1afb
commit
fff0f11b33
21 changed files with 252 additions and 44 deletions
|
@ -48,6 +48,7 @@ int Add::execute(const QStringList& arguments)
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
|
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
|
@ -89,7 +90,10 @@ int Add::execute(const QStringList& arguments)
|
||||||
const QString& databasePath = args.at(0);
|
const QString& databasePath = args.at(0);
|
||||||
const QString& entryPath = args.at(1);
|
const QString& entryPath = args.at(1);
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(databasePath, parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(databasePath,
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +121,10 @@ int Add::execute(const QStringList& arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(prompt)) {
|
if (parser.isSet(prompt)) {
|
||||||
outputTextStream << QObject::tr("Enter password for new entry: ") << flush;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
QString password = Utils::getPassword();
|
outputTextStream << QObject::tr("Enter password for new entry: ") << flush;
|
||||||
|
}
|
||||||
|
QString password = Utils::getPassword(parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||||
entry->setPassword(password);
|
entry->setPassword(password);
|
||||||
} else if (parser.isSet(generate)) {
|
} else if (parser.isSet(generate)) {
|
||||||
PasswordGenerator passwordGenerator;
|
PasswordGenerator passwordGenerator;
|
||||||
|
@ -141,6 +147,8 @@ int Add::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
outputTextStream << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
|
outputTextStream << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl;
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ int Clip::execute(const QStringList& arguments)
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
parser.addOption(keyFile);
|
parser.addOption(keyFile);
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption totp(QStringList() << "t" << "totp",
|
QCommandLineOption totp(QStringList() << "t" << "totp",
|
||||||
QObject::tr("Copy the current TOTP to the clipboard."));
|
QObject::tr("Copy the current TOTP to the clipboard."));
|
||||||
parser.addOption(totp);
|
parser.addOption(totp);
|
||||||
|
@ -66,15 +67,22 @@ int Clip::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return clipEntry(db, args.at(1), args.value(2), parser.isSet(totp));
|
return clipEntry(db, args.at(1), args.value(2), parser.isSet(totp), parser.isSet(Command::QuietOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Clip::clipEntry(QSharedPointer<Database> database, const QString& entryPath, const QString& timeout, bool clipTotp)
|
int Clip::clipEntry(QSharedPointer<Database> database,
|
||||||
|
const QString& entryPath,
|
||||||
|
const QString& timeout,
|
||||||
|
bool clipTotp,
|
||||||
|
bool silent)
|
||||||
{
|
{
|
||||||
TextStream err(Utils::STDERR);
|
TextStream err(Utils::STDERR);
|
||||||
|
|
||||||
|
@ -86,7 +94,7 @@ int Clip::clipEntry(QSharedPointer<Database> database, const QString& entryPath,
|
||||||
timeoutSeconds = timeout.toInt();
|
timeoutSeconds = timeout.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(silent ? Utils::DEVNULL : Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
err << QObject::tr("Entry %1 not found.").arg(entryPath) << endl;
|
err << QObject::tr("Entry %1 not found.").arg(entryPath) << endl;
|
||||||
|
|
|
@ -26,7 +26,11 @@ public:
|
||||||
Clip();
|
Clip();
|
||||||
~Clip();
|
~Clip();
|
||||||
int execute(const QStringList& arguments) override;
|
int execute(const QStringList& arguments) override;
|
||||||
int clipEntry(QSharedPointer<Database> database, const QString& entryPath, const QString& timeout, bool clipTotp);
|
int clipEntry(QSharedPointer<Database> database,
|
||||||
|
const QString& entryPath,
|
||||||
|
const QString& timeout,
|
||||||
|
bool clipTotp,
|
||||||
|
bool silent);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_CLIP_H
|
#endif // KEEPASSXC_CLIP_H
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
#include "Remove.h"
|
#include "Remove.h"
|
||||||
#include "Show.h"
|
#include "Show.h"
|
||||||
|
|
||||||
|
const QCommandLineOption Command::QuietOption =
|
||||||
|
QCommandLineOption(QStringList() << "q"
|
||||||
|
<< "quiet",
|
||||||
|
QObject::tr("Silence password prompt and other secondary outputs."));
|
||||||
QMap<QString, Command*> commands;
|
QMap<QString, Command*> commands;
|
||||||
|
|
||||||
Command::~Command()
|
Command::~Command()
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#ifndef KEEPASSXC_COMMAND_H
|
#ifndef KEEPASSXC_COMMAND_H
|
||||||
#define KEEPASSXC_COMMAND_H
|
#define KEEPASSXC_COMMAND_H
|
||||||
|
|
||||||
|
#include <QCommandLineOption>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
@ -36,6 +37,8 @@ public:
|
||||||
|
|
||||||
static QList<Command*> getCommands();
|
static QList<Command*> getCommands();
|
||||||
static Command* getCommand(const QString& commandName);
|
static Command* getCommand(const QString& commandName);
|
||||||
|
|
||||||
|
static const QCommandLineOption QuietOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_COMMAND_H
|
#endif // KEEPASSXC_COMMAND_H
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "core/PassphraseGenerator.h"
|
#include "core/PassphraseGenerator.h"
|
||||||
#include "Utils.h"
|
|
||||||
|
|
||||||
Diceware::Diceware()
|
Diceware::Diceware()
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,6 +48,7 @@ int Edit::execute(const QStringList& arguments)
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
|
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
|
@ -93,7 +94,10 @@ int Edit::execute(const QStringList& arguments)
|
||||||
const QString& databasePath = args.at(0);
|
const QString& databasePath = args.at(0);
|
||||||
const QString& entryPath = args.at(1);
|
const QString& entryPath = args.at(1);
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(databasePath, parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(databasePath,
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -132,8 +136,10 @@ int Edit::execute(const QStringList& arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(prompt)) {
|
if (parser.isSet(prompt)) {
|
||||||
out << QObject::tr("Enter new password for entry: ") << flush;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
QString password = Utils::getPassword();
|
out << QObject::tr("Enter new password for entry: ") << flush;
|
||||||
|
}
|
||||||
|
QString password = Utils::getPassword(parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||||
entry->setPassword(password);
|
entry->setPassword(password);
|
||||||
} else if (parser.isSet(generate)) {
|
} else if (parser.isSet(generate)) {
|
||||||
PasswordGenerator passwordGenerator;
|
PasswordGenerator passwordGenerator;
|
||||||
|
@ -158,6 +164,8 @@ int Edit::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << endl;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
|
out << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << endl;
|
||||||
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ int Extract::execute(const QStringList& arguments)
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database to extract."));
|
parser.addPositionalArgument("database", QObject::tr("Path of the database to extract."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
@ -62,11 +63,13 @@ int Extract::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << QObject::tr("Insert password to unlock %1: ").arg(args.at(0)) << flush;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
|
out << QObject::tr("Insert password to unlock %1: ").arg(args.at(0)) << flush;
|
||||||
|
}
|
||||||
|
|
||||||
auto compositeKey = QSharedPointer<CompositeKey>::create();
|
auto compositeKey = QSharedPointer<CompositeKey>::create();
|
||||||
|
|
||||||
QString line = Utils::getPassword();
|
QString line = Utils::getPassword(parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||||
auto passwordKey = QSharedPointer<PasswordKey>::create();
|
auto passwordKey = QSharedPointer<PasswordKey>::create();
|
||||||
passwordKey->setPassword(line);
|
passwordKey->setPassword(line);
|
||||||
compositeKey->addKey(passwordKey);
|
compositeKey->addKey(passwordKey);
|
||||||
|
|
|
@ -46,6 +46,7 @@ int List::execute(const QStringList& arguments)
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||||
parser.addPositionalArgument("group", QObject::tr("Path of the group to list. Default is /"), "[group]");
|
parser.addPositionalArgument("group", QObject::tr("Path of the group to list. Default is /"), "[group]");
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
@ -64,7 +65,10 @@ int List::execute(const QStringList& arguments)
|
||||||
|
|
||||||
bool recursive = parser.isSet(recursiveOption);
|
bool recursive = parser.isSet(recursiveOption);
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Global.h"
|
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
|
#include "core/Global.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
|
|
||||||
Locate::Locate()
|
Locate::Locate()
|
||||||
|
@ -48,6 +48,7 @@ int Locate::execute(const QStringList& arguments)
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||||
parser.addPositionalArgument("term", QObject::tr("Search term."));
|
parser.addPositionalArgument("term", QObject::tr("Search term."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
@ -61,7 +62,10 @@ int Locate::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Merger.h"
|
#include "core/Merger.h"
|
||||||
#include "cli/Utils.h"
|
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
@ -45,10 +45,11 @@ int Merge::execute(const QStringList& arguments)
|
||||||
parser.setApplicationDescription(description);
|
parser.setApplicationDescription(description);
|
||||||
parser.addPositionalArgument("database1", QObject::tr("Path of the database to merge into."));
|
parser.addPositionalArgument("database1", QObject::tr("Path of the database to merge into."));
|
||||||
parser.addPositionalArgument("database2", QObject::tr("Path of the database to merge from."));
|
parser.addPositionalArgument("database2", QObject::tr("Path of the database to merge from."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
|
|
||||||
QCommandLineOption samePasswordOption(QStringList() << "s" << "same-credentials",
|
QCommandLineOption samePasswordOption(QStringList() << "s" << "same-credentials",
|
||||||
QObject::tr("Use the same credentials for both database files."));
|
QObject::tr("Use the same credentials for both database files."));
|
||||||
|
parser.addOption(samePasswordOption);
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
@ -58,7 +59,6 @@ int Merge::execute(const QStringList& arguments)
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
parser.addOption(keyFileFrom);
|
parser.addOption(keyFileFrom);
|
||||||
|
|
||||||
parser.addOption(samePasswordOption);
|
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
parser.process(arguments);
|
parser.process(arguments);
|
||||||
|
|
||||||
|
@ -68,14 +68,20 @@ int Merge::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db1 = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db1 = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db1) {
|
if (!db1) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Database> db2;
|
QSharedPointer<Database> db2;
|
||||||
if (!parser.isSet("same-credentials")) {
|
if (!parser.isSet("same-credentials")) {
|
||||||
db2 = Database::unlockFromStdin(args.at(1), parser.value(keyFileFrom), Utils::STDOUT, Utils::STDERR);
|
db2 = Database::unlockFromStdin(args.at(1),
|
||||||
|
parser.value(keyFileFrom),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
} else {
|
} else {
|
||||||
db2 = QSharedPointer<Database>::create();
|
db2 = QSharedPointer<Database>::create();
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
|
@ -94,8 +100,10 @@ int Merge::execute(const QStringList& arguments)
|
||||||
err << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << endl;
|
err << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
out << "Successfully merged the database files." << endl;
|
if (!parser.isSet(Command::QuietOption)) {
|
||||||
} else {
|
out << "Successfully merged the database files." << endl;
|
||||||
|
}
|
||||||
|
} else if (!parser.isSet(Command::QuietOption)) {
|
||||||
out << "Database was not modified by merge operation." << endl;
|
out << "Database was not modified by merge operation." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ int Remove::execute(const QStringList& arguments)
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QCoreApplication::tr("main", "Remove an entry from the database."));
|
parser.setApplicationDescription(QCoreApplication::tr("main", "Remove an entry from the database."));
|
||||||
parser.addPositionalArgument("database", QCoreApplication::tr("main", "Path of the database."));
|
parser.addPositionalArgument("database", QCoreApplication::tr("main", "Path of the database."));
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
QCommandLineOption keyFile(QStringList() << "k" << "key-file",
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
@ -63,17 +64,20 @@ int Remove::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return removeEntry(db.data(), args.at(0), args.at(1));
|
return removeEntry(db.data(), args.at(0), args.at(1), parser.isSet(Command::QuietOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Remove::removeEntry(Database* database, const QString& databasePath, const QString& entryPath)
|
int Remove::removeEntry(Database* database, const QString& databasePath, const QString& entryPath, bool quiet)
|
||||||
{
|
{
|
||||||
TextStream out(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream out(quiet ? Utils::DEVNULL : Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream err(Utils::STDERR, QIODevice::WriteOnly);
|
TextStream err(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QPointer<Entry> entry = database->rootGroup()->findEntryByPath(entryPath);
|
QPointer<Entry> entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
Remove();
|
Remove();
|
||||||
~Remove();
|
~Remove();
|
||||||
int execute(const QStringList& arguments) override;
|
int execute(const QStringList& arguments) override;
|
||||||
int removeEntry(Database* database, const QString& databasePath, const QString& entryPath);
|
int removeEntry(Database* database, const QString& databasePath, const QString& entryPath, bool quiet);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_REMOVE_H
|
#endif // KEEPASSXC_REMOVE_H
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "core/Group.h"
|
|
||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
#include "Utils.h"
|
#include "core/Group.h"
|
||||||
|
|
||||||
Show::Show()
|
Show::Show()
|
||||||
{
|
{
|
||||||
|
@ -50,6 +50,7 @@ int Show::execute(const QStringList& arguments)
|
||||||
QObject::tr("Key file of the database."),
|
QObject::tr("Key file of the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
parser.addOption(keyFile);
|
parser.addOption(keyFile);
|
||||||
|
parser.addOption(Command::QuietOption);
|
||||||
QCommandLineOption totp(QStringList() << "t" << "totp",
|
QCommandLineOption totp(QStringList() << "t" << "totp",
|
||||||
QObject::tr("Show the entry's current TOTP."));
|
QObject::tr("Show the entry's current TOTP."));
|
||||||
parser.addOption(totp);
|
parser.addOption(totp);
|
||||||
|
@ -71,7 +72,10 @@ int Show::execute(const QStringList& arguments)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db = Database::unlockFromStdin(args.at(0), parser.value(keyFile), Utils::STDOUT, Utils::STDERR);
|
auto db = Database::unlockFromStdin(args.at(0),
|
||||||
|
parser.value(keyFile),
|
||||||
|
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
|
Utils::STDERR);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,4 +47,4 @@ private:
|
||||||
void detectCodec();
|
void detectCodec();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //KEEPASSXC_TEXTSTREAM_H
|
#endif // KEEPASSXC_TEXTSTREAM_H
|
||||||
|
|
|
@ -43,6 +43,16 @@ FILE* STDERR = stderr;
|
||||||
*/
|
*/
|
||||||
FILE* STDIN = stdin;
|
FILE* STDIN = stdin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEVNULL file handle for the CLI.
|
||||||
|
*/
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
FILE* DEVNULL = fopen("nul", "w");
|
||||||
|
#else
|
||||||
|
FILE* DEVNULL = fopen("/dev/null", "w");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void setStdinEcho(bool enable = true)
|
void setStdinEcho(bool enable = true)
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
@ -95,9 +105,9 @@ void setNextPassword(const QString& password)
|
||||||
*
|
*
|
||||||
* @return the password
|
* @return the password
|
||||||
*/
|
*/
|
||||||
QString getPassword()
|
QString getPassword(FILE* outputDescriptor)
|
||||||
{
|
{
|
||||||
TextStream out(STDOUT, QIODevice::WriteOnly);
|
TextStream out(outputDescriptor, QIODevice::WriteOnly);
|
||||||
|
|
||||||
// return preset password if one is set
|
// return preset password if one is set
|
||||||
if (!Test::nextPasswords.isEmpty()) {
|
if (!Test::nextPasswords.isEmpty()) {
|
||||||
|
|
|
@ -26,9 +26,10 @@ namespace Utils
|
||||||
extern FILE* STDOUT;
|
extern FILE* STDOUT;
|
||||||
extern FILE* STDERR;
|
extern FILE* STDERR;
|
||||||
extern FILE* STDIN;
|
extern FILE* STDIN;
|
||||||
|
extern FILE* DEVNULL;
|
||||||
|
|
||||||
void setStdinEcho(bool enable);
|
void setStdinEcho(bool enable);
|
||||||
QString getPassword();
|
QString getPassword(FILE* outputDescriptor = STDOUT);
|
||||||
int clipText(const QString& text);
|
int clipText(const QString& text);
|
||||||
|
|
||||||
namespace Test
|
namespace Test
|
||||||
|
|
|
@ -56,6 +56,9 @@ Shows the title, username, password, URL and notes of a database entry. Can also
|
||||||
.IP "-k, --key-file <path>"
|
.IP "-k, --key-file <path>"
|
||||||
Specifies a path to a key file for unlocking the database. In a merge operation this option is used to specify the key file path for the first database.
|
Specifies a path to a key file for unlocking the database. In a merge operation this option is used to specify the key file path for the first database.
|
||||||
|
|
||||||
|
.IP "-q, --quiet <path>"
|
||||||
|
Silence password prompt and other secondary outputs.
|
||||||
|
|
||||||
.IP "-h, --help"
|
.IP "-h, --help"
|
||||||
Displays help information.
|
Displays help information.
|
||||||
|
|
||||||
|
|
|
@ -708,10 +708,9 @@ QSharedPointer<Database> Database::unlockFromStdin(const QString& databaseFilena
|
||||||
TextStream out(outputDescriptor);
|
TextStream out(outputDescriptor);
|
||||||
TextStream err(errorDescriptor);
|
TextStream err(errorDescriptor);
|
||||||
|
|
||||||
out << QObject::tr("Insert password to unlock %1: ").arg(databaseFilename);
|
out << QObject::tr("Insert password to unlock %1: ").arg(databaseFilename) << flush;
|
||||||
out.flush();
|
|
||||||
|
|
||||||
QString line = Utils::getPassword();
|
QString line = Utils::getPassword(outputDescriptor);
|
||||||
auto passwordKey = QSharedPointer<PasswordKey>::create();
|
auto passwordKey = QSharedPointer<PasswordKey>::create();
|
||||||
passwordKey->setPassword(line);
|
passwordKey->setPassword(line);
|
||||||
compositeKey->addKey(passwordKey);
|
compositeKey->addKey(passwordKey);
|
||||||
|
|
|
@ -161,6 +161,9 @@ void TestCli::testAdd()
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
addCmd.execute({"add", "-u", "newuser", "--url", "https://example.com/", "-g", "-l", "20", m_dbFile->fileName(), "/newuser-entry"});
|
addCmd.execute({"add", "-u", "newuser", "--url", "https://example.com/", "-g", "-l", "20", m_dbFile->fileName(), "/newuser-entry"});
|
||||||
m_stderrFile->reset();
|
m_stderrFile->reset();
|
||||||
|
m_stdoutFile->reset();
|
||||||
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Successfully added entry newuser-entry.\n"));
|
||||||
|
|
||||||
auto db = readTestDatabase();
|
auto db = readTestDatabase();
|
||||||
auto* entry = db->rootGroup()->findEntryByPath("/newuser-entry");
|
auto* entry = db->rootGroup()->findEntryByPath("/newuser-entry");
|
||||||
|
@ -169,6 +172,16 @@ void TestCli::testAdd()
|
||||||
QCOMPARE(entry->url(), QString("https://example.com/"));
|
QCOMPARE(entry->url(), QString("https://example.com/"));
|
||||||
QCOMPARE(entry->password().size(), 20);
|
QCOMPARE(entry->password().size(), 20);
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
|
qint64 pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
addCmd.execute({"add", "-q", "-u", "newuser", "-g", "-l", "20", m_dbFile->fileName(), "/newentry-quiet"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
|
db = readTestDatabase();
|
||||||
|
entry = db->rootGroup()->findEntryByPath("/newentry-quiet");
|
||||||
|
QVERIFY(entry);
|
||||||
|
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
Utils::Test::setNextPassword("newpassword");
|
Utils::Test::setNextPassword("newpassword");
|
||||||
addCmd.execute({"add", "-u", "newuser2", "--url", "https://example.net/", "-g", "-l", "20", "-p", m_dbFile->fileName(), "/newuser-entry2"});
|
addCmd.execute({"add", "-u", "newuser2", "--url", "https://example.net/", "-g", "-l", "20", "-p", m_dbFile->fileName(), "/newuser-entry2"});
|
||||||
|
@ -181,7 +194,8 @@ void TestCli::testAdd()
|
||||||
QCOMPARE(entry->password(), QString("newpassword"));
|
QCOMPARE(entry->password(), QString("newpassword"));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isTOTP(const QString & value) {
|
bool isTOTP(const QString& value)
|
||||||
|
{
|
||||||
QString val = value.trimmed();
|
QString val = value.trimmed();
|
||||||
if (val.length() < 5 || val.length() > 6) {
|
if (val.length() < 5 || val.length() > 6) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -208,6 +222,7 @@ void TestCli::testClip()
|
||||||
clipCmd.execute({"clip", m_dbFile->fileName(), "/Sample Entry"});
|
clipCmd.execute({"clip", m_dbFile->fileName(), "/Sample Entry"});
|
||||||
|
|
||||||
m_stderrFile->reset();
|
m_stderrFile->reset();
|
||||||
|
m_stdoutFile->reset();
|
||||||
QString errorOutput(m_stderrFile->readAll());
|
QString errorOutput(m_stderrFile->readAll());
|
||||||
|
|
||||||
if (errorOutput.contains("Unable to start program")
|
if (errorOutput.contains("Unable to start program")
|
||||||
|
@ -215,6 +230,17 @@ void TestCli::testClip()
|
||||||
QSKIP("Clip test skipped due to missing clipboard tool");
|
QSKIP("Clip test skipped due to missing clipboard tool");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QCOMPARE(clipboard->text(), QString("Password"));
|
||||||
|
m_stdoutFile->readLine(); // skip prompt line
|
||||||
|
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Entry's password copied to the clipboard!\n"));
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
|
qint64 pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
clipCmd.execute({"clip", m_dbFile->fileName(), "/Sample Entry", "-q"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
// Output should be empty when quiet option is set.
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
QCOMPARE(clipboard->text(), QString("Password"));
|
QCOMPARE(clipboard->text(), QString("Password"));
|
||||||
|
|
||||||
// TOTP
|
// TOTP
|
||||||
|
@ -284,7 +310,7 @@ void TestCli::testDiceware()
|
||||||
const auto words = passphrase.split(" ");
|
const auto words = passphrase.split(" ");
|
||||||
QCOMPARE(words.size(), 11);
|
QCOMPARE(words.size(), 11);
|
||||||
QRegularExpression regex("^word\\d+$");
|
QRegularExpression regex("^word\\d+$");
|
||||||
for (const auto& word: words) {
|
for (const auto& word : words) {
|
||||||
QVERIFY2(regex.match(word).hasMatch(), qPrintable("Word " + word + " was not on the word list"));
|
QVERIFY2(regex.match(word).hasMatch(), qPrintable("Word " + word + " was not on the word list"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,6 +323,9 @@ void TestCli::testEdit()
|
||||||
|
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
editCmd.execute({"edit", "-u", "newuser", "--url", "https://otherurl.example.com/", "-t", "newtitle", m_dbFile->fileName(), "/Sample Entry"});
|
editCmd.execute({"edit", "-u", "newuser", "--url", "https://otherurl.example.com/", "-t", "newtitle", m_dbFile->fileName(), "/Sample Entry"});
|
||||||
|
m_stdoutFile->reset();
|
||||||
|
m_stdoutFile->readLine(); // skip prompt line
|
||||||
|
QCOMPARE(m_stdoutFile->readLine(), QByteArray("Successfully edited entry newtitle.\n"));
|
||||||
|
|
||||||
auto db = readTestDatabase();
|
auto db = readTestDatabase();
|
||||||
auto* entry = db->rootGroup()->findEntryByPath("/newtitle");
|
auto* entry = db->rootGroup()->findEntryByPath("/newtitle");
|
||||||
|
@ -305,6 +334,13 @@ void TestCli::testEdit()
|
||||||
QCOMPARE(entry->url(), QString("https://otherurl.example.com/"));
|
QCOMPARE(entry->url(), QString("https://otherurl.example.com/"));
|
||||||
QCOMPARE(entry->password(), QString("Password"));
|
QCOMPARE(entry->password(), QString("Password"));
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
|
qint64 pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
editCmd.execute({"edit", m_dbFile->fileName(), "-q", "-t", "newtitle", "/Sample Entry"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
|
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
editCmd.execute({"edit", "-g", m_dbFile->fileName(), "/newtitle"});
|
editCmd.execute({"edit", "-g", m_dbFile->fileName(), "/newtitle"});
|
||||||
db = readTestDatabase();
|
db = readTestDatabase();
|
||||||
|
@ -430,7 +466,7 @@ void TestCli::testEstimate()
|
||||||
QVERIFY(result.startsWith("Length " + length));
|
QVERIFY(result.startsWith("Length " + length));
|
||||||
QVERIFY(result.contains("Entropy " + entropy));
|
QVERIFY(result.contains("Entropy " + entropy));
|
||||||
QVERIFY(result.contains("Log10 " + log10));
|
QVERIFY(result.contains("Log10 " + log10));
|
||||||
for (const auto& string: asConst(searchStrings)) {
|
for (const auto& string : asConst(searchStrings)) {
|
||||||
QVERIFY2(result.contains(string), qPrintable("String " + string + " missing"));
|
QVERIFY2(result.contains(string), qPrintable("String " + string + " missing"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -455,6 +491,18 @@ void TestCli::testExtract()
|
||||||
auto* entry = db->rootGroup()->findEntryByPath("/Sample Entry");
|
auto* entry = db->rootGroup()->findEntryByPath("/Sample Entry");
|
||||||
QVERIFY(entry);
|
QVERIFY(entry);
|
||||||
QCOMPARE(entry->password(), QString("Password"));
|
QCOMPARE(entry->password(), QString("Password"));
|
||||||
|
|
||||||
|
m_stdoutFile->reset();
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
|
QScopedPointer<Database> dbQuiet(new Database());
|
||||||
|
qint64 pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
extractCmd.execute({"extract", "-q", m_dbFile->fileName()});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
reader.readDatabase(m_stdoutFile.data(), dbQuiet.data());
|
||||||
|
QVERIFY(!reader.hasError());
|
||||||
|
QVERIFY(db.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCli::testGenerate_data()
|
void TestCli::testGenerate_data()
|
||||||
|
@ -533,8 +581,22 @@ void TestCli::testList()
|
||||||
"eMail/\n"
|
"eMail/\n"
|
||||||
"Homebanking/\n"));
|
"Homebanking/\n"));
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
qint64 pos = m_stdoutFile->pos();
|
qint64 pos = m_stdoutFile->pos();
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
|
listCmd.execute({"ls", "-q", m_dbFile->fileName()});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Sample Entry\n"
|
||||||
|
"General/\n"
|
||||||
|
"Windows/\n"
|
||||||
|
"Network/\n"
|
||||||
|
"Internet/\n"
|
||||||
|
"eMail/\n"
|
||||||
|
"Homebanking/\n"));
|
||||||
|
|
||||||
|
|
||||||
|
pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
listCmd.execute({"ls", "-R", m_dbFile->fileName()});
|
listCmd.execute({"ls", "-R", m_dbFile->fileName()});
|
||||||
m_stdoutFile->seek(pos);
|
m_stdoutFile->seek(pos);
|
||||||
m_stdoutFile->readLine(); // skip password prompt
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
|
@ -581,8 +643,15 @@ void TestCli::testLocate()
|
||||||
m_stdoutFile->readLine(); // skip password prompt
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
QCOMPARE(m_stdoutFile->readAll(), QByteArray("/Sample Entry\n"));
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("/Sample Entry\n"));
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
qint64 pos = m_stdoutFile->pos();
|
qint64 pos = m_stdoutFile->pos();
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
|
locateCmd.execute({"locate", m_dbFile->fileName(), "-q", "Sample"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("/Sample Entry\n"));
|
||||||
|
|
||||||
|
pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
locateCmd.execute({"locate", m_dbFile->fileName(), "Does Not Exist"});
|
locateCmd.execute({"locate", m_dbFile->fileName(), "Does Not Exist"});
|
||||||
m_stdoutFile->seek(pos);
|
m_stdoutFile->seek(pos);
|
||||||
m_stdoutFile->readLine(); // skip password prompt
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
|
@ -709,6 +778,13 @@ void TestCli::testMerge()
|
||||||
m_stdoutFile->seek(pos);
|
m_stdoutFile->seek(pos);
|
||||||
m_stdoutFile->readLine();
|
m_stdoutFile->readLine();
|
||||||
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Database was not modified by merge operation.\n"));
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Database was not modified by merge operation.\n"));
|
||||||
|
|
||||||
|
// Quiet option
|
||||||
|
pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
mergeCmd.execute({"merge", "-q", "-s", sourceFile.fileName(), sourceFile.fileName()});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCli::testRemove()
|
void TestCli::testRemove()
|
||||||
|
@ -779,6 +855,52 @@ void TestCli::testRemove()
|
||||||
QCOMPARE(m_stderrFile->readAll(), QByteArray("Entry /Sample Entry not found.\n"));
|
QCOMPARE(m_stderrFile->readAll(), QByteArray("Entry /Sample Entry not found.\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCli::testRemoveQuiet()
|
||||||
|
{
|
||||||
|
Remove removeCmd;
|
||||||
|
QVERIFY(!removeCmd.name.isEmpty());
|
||||||
|
QVERIFY(removeCmd.getDescriptionLine().contains(removeCmd.name));
|
||||||
|
|
||||||
|
Kdbx3Reader reader;
|
||||||
|
Kdbx3Writer writer;
|
||||||
|
|
||||||
|
qint64 pos = m_stdoutFile->pos();
|
||||||
|
|
||||||
|
// delete entry and verify
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
removeCmd.execute({"rm", "-q", m_dbFile->fileName(), "/Sample Entry"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
|
|
||||||
|
auto key = QSharedPointer<CompositeKey>::create();
|
||||||
|
key->addKey(QSharedPointer<PasswordKey>::create("a"));
|
||||||
|
QFile readBack(m_dbFile->fileName());
|
||||||
|
readBack.open(QIODevice::ReadOnly);
|
||||||
|
auto readBackDb = QSharedPointer<Database>::create();
|
||||||
|
reader.readDatabase(&readBack, key, readBackDb.data());
|
||||||
|
readBack.close();
|
||||||
|
QVERIFY(readBackDb);
|
||||||
|
QVERIFY(!readBackDb->rootGroup()->findEntryByPath("/Sample Entry"));
|
||||||
|
QVERIFY(readBackDb->rootGroup()->findEntryByPath("/Recycle Bin/Sample Entry"));
|
||||||
|
|
||||||
|
pos = m_stdoutFile->pos();
|
||||||
|
|
||||||
|
// remove the entry completely
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
|
removeCmd.execute({"rm", "-q", m_dbFile->fileName(), "/Recycle Bin/Sample Entry"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray(""));
|
||||||
|
|
||||||
|
readBack.setFileName(m_dbFile->fileName());
|
||||||
|
readBack.open(QIODevice::ReadOnly);
|
||||||
|
readBackDb = QSharedPointer<Database>::create();
|
||||||
|
reader.readDatabase(&readBack, key, readBackDb.data());
|
||||||
|
readBack.close();
|
||||||
|
QVERIFY(readBackDb);
|
||||||
|
QVERIFY(!readBackDb->rootGroup()->findEntryByPath("/Sample Entry"));
|
||||||
|
QVERIFY(!readBackDb->rootGroup()->findEntryByPath("/Recycle Bin/Sample Entry"));
|
||||||
|
}
|
||||||
|
|
||||||
void TestCli::testShow()
|
void TestCli::testShow()
|
||||||
{
|
{
|
||||||
Show showCmd;
|
Show showCmd;
|
||||||
|
@ -797,6 +919,16 @@ void TestCli::testShow()
|
||||||
|
|
||||||
qint64 pos = m_stdoutFile->pos();
|
qint64 pos = m_stdoutFile->pos();
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
|
showCmd.execute({"show", m_dbFile->fileName(), "-q", "/Sample Entry"});
|
||||||
|
m_stdoutFile->seek(pos);
|
||||||
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Title: Sample Entry\n"
|
||||||
|
"UserName: User Name\n"
|
||||||
|
"Password: Password\n"
|
||||||
|
"URL: http://www.somesite.com/\n"
|
||||||
|
"Notes: Notes\n"));
|
||||||
|
|
||||||
|
pos = m_stdoutFile->pos();
|
||||||
|
Utils::Test::setNextPassword("a");
|
||||||
showCmd.execute({"show", "-a", "Title", m_dbFile->fileName(), "/Sample Entry"});
|
showCmd.execute({"show", "-a", "Title", m_dbFile->fileName(), "/Sample Entry"});
|
||||||
m_stdoutFile->seek(pos);
|
m_stdoutFile->seek(pos);
|
||||||
m_stdoutFile->readLine(); // skip password prompt
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
|
|
|
@ -54,6 +54,7 @@ private slots:
|
||||||
void testLocate();
|
void testLocate();
|
||||||
void testMerge();
|
void testMerge();
|
||||||
void testRemove();
|
void testRemove();
|
||||||
|
void testRemoveQuiet();
|
||||||
void testShow();
|
void testShow();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue