mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-25 22:16:01 -05: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
112
src/cli/Add.cpp
112
src/cli/Add.cpp
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,8 +20,6 @@
|
||||
|
||||
#include "Add.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
@ -29,106 +27,84 @@
|
||||
#include "core/Group.h"
|
||||
#include "core/PasswordGenerator.h"
|
||||
|
||||
const QCommandLineOption Add::UsernameOption = QCommandLineOption(QStringList() << "u"
|
||||
<< "username",
|
||||
QObject::tr("Username for the entry."),
|
||||
QObject::tr("username"));
|
||||
|
||||
const QCommandLineOption Add::UrlOption =
|
||||
QCommandLineOption(QStringList() << "url", QObject::tr("URL for the entry."), QObject::tr("URL"));
|
||||
|
||||
const QCommandLineOption Add::PasswordPromptOption =
|
||||
QCommandLineOption(QStringList() << "p"
|
||||
<< "password-prompt",
|
||||
QObject::tr("Prompt for the entry's password."));
|
||||
|
||||
const QCommandLineOption Add::GenerateOption = QCommandLineOption(QStringList() << "g"
|
||||
<< "generate",
|
||||
QObject::tr("Generate a password for the entry."));
|
||||
|
||||
const QCommandLineOption Add::PasswordLengthOption =
|
||||
QCommandLineOption(QStringList() << "l"
|
||||
<< "password-length",
|
||||
QObject::tr("Length for the generated password."),
|
||||
QObject::tr("length"));
|
||||
|
||||
Add::Add()
|
||||
{
|
||||
name = QString("add");
|
||||
description = QObject::tr("Add a new entry to a database.");
|
||||
options.append(Add::UsernameOption);
|
||||
options.append(Add::UrlOption);
|
||||
options.append(Add::PasswordPromptOption);
|
||||
options.append(Add::GenerateOption);
|
||||
options.append(Add::PasswordLengthOption);
|
||||
positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to add."), QString("")});
|
||||
}
|
||||
|
||||
Add::~Add()
|
||||
{
|
||||
}
|
||||
|
||||
int Add::execute(const QStringList& arguments)
|
||||
int Add::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption username(QStringList() << "u"
|
||||
<< "username",
|
||||
QObject::tr("Username for the entry."),
|
||||
QObject::tr("username"));
|
||||
parser.addOption(username);
|
||||
|
||||
QCommandLineOption url(QStringList() << "url", QObject::tr("URL for the entry."), QObject::tr("URL"));
|
||||
parser.addOption(url);
|
||||
|
||||
QCommandLineOption prompt(QStringList() << "p"
|
||||
<< "password-prompt",
|
||||
QObject::tr("Prompt for the entry's password."));
|
||||
parser.addOption(prompt);
|
||||
|
||||
QCommandLineOption generate(QStringList() << "g"
|
||||
<< "generate",
|
||||
QObject::tr("Generate a password for the entry."));
|
||||
parser.addOption(generate);
|
||||
|
||||
QCommandLineOption length(QStringList() << "l"
|
||||
<< "password-length",
|
||||
QObject::tr("Length for the generated password."),
|
||||
QObject::tr("length"));
|
||||
parser.addOption(length);
|
||||
|
||||
parser.addPositionalArgument("entry", QObject::tr("Path of the entry to add."));
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "add [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
const QString& databasePath = args.at(0);
|
||||
const QString& entryPath = args.at(1);
|
||||
|
||||
auto db = Utils::unlockDatabase(databasePath,
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Validating the password length here, before we actually create
|
||||
// the entry.
|
||||
QString passwordLength = parser.value(length);
|
||||
QString passwordLength = parser->value(Add::PasswordLengthOption);
|
||||
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
||||
errorTextStream << QObject::tr("Invalid value for password length %1.").arg(passwordLength) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Entry* entry = db->rootGroup()->addEntryWithPath(entryPath);
|
||||
Entry* entry = database->rootGroup()->addEntryWithPath(entryPath);
|
||||
if (!entry) {
|
||||
errorTextStream << QObject::tr("Could not create entry with path %1.").arg(entryPath) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!parser.value("username").isEmpty()) {
|
||||
entry->setUsername(parser.value("username"));
|
||||
if (!parser->value(Add::UsernameOption).isEmpty()) {
|
||||
entry->setUsername(parser->value(Add::UsernameOption));
|
||||
}
|
||||
|
||||
if (!parser.value("url").isEmpty()) {
|
||||
entry->setUrl(parser.value("url"));
|
||||
if (!parser->value(Add::UrlOption).isEmpty()) {
|
||||
entry->setUrl(parser->value(Add::UrlOption));
|
||||
}
|
||||
|
||||
if (parser.isSet(prompt)) {
|
||||
if (!parser.isSet(Command::QuietOption)) {
|
||||
if (parser->isSet(Add::PasswordPromptOption)) {
|
||||
if (!parser->isSet(Command::QuietOption)) {
|
||||
outputTextStream << QObject::tr("Enter password for new entry: ") << flush;
|
||||
}
|
||||
QString password = Utils::getPassword(parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||
QString password = Utils::getPassword(parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||
entry->setPassword(password);
|
||||
} else if (parser.isSet(generate)) {
|
||||
} else if (parser->isSet(Add::GenerateOption)) {
|
||||
PasswordGenerator passwordGenerator;
|
||||
|
||||
if (passwordLength.isEmpty()) {
|
||||
@ -144,12 +120,12 @@ int Add::execute(const QStringList& arguments)
|
||||
}
|
||||
|
||||
QString errorMessage;
|
||||
if (!db->save(databasePath, &errorMessage, true, false)) {
|
||||
if (!database->save(databasePath, &errorMessage, true, false)) {
|
||||
errorTextStream << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!parser.isSet(Command::QuietOption)) {
|
||||
if (!parser->isSet(Command::QuietOption)) {
|
||||
outputTextStream << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,14 +18,21 @@
|
||||
#ifndef KEEPASSXC_ADD_H
|
||||
#define KEEPASSXC_ADD_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Add : public Command
|
||||
class Add : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Add();
|
||||
~Add();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption UsernameOption;
|
||||
static const QCommandLineOption UrlOption;
|
||||
static const QCommandLineOption PasswordPromptOption;
|
||||
static const QCommandLineOption GenerateOption;
|
||||
static const QCommandLineOption PasswordLengthOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_ADD_H
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2017 KeePassXC Team
|
||||
# Copyright (C) 2019 KeePassXC Team
|
||||
#
|
||||
# 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
|
||||
@ -18,6 +18,7 @@ set(cli_SOURCES
|
||||
Clip.cpp
|
||||
Create.cpp
|
||||
Command.cpp
|
||||
DatabaseCommand.cpp
|
||||
Diceware.cpp
|
||||
Edit.cpp
|
||||
Estimate.cpp
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -22,80 +22,52 @@
|
||||
|
||||
#include "Clip.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
|
||||
const QCommandLineOption Clip::TotpOption = QCommandLineOption(QStringList() << "t"
|
||||
<< "totp",
|
||||
QObject::tr("Copy the current TOTP to the clipboard."));
|
||||
|
||||
Clip::Clip()
|
||||
{
|
||||
name = QString("clip");
|
||||
description = QObject::tr("Copy an entry's password to the clipboard.");
|
||||
options.append(Clip::TotpOption);
|
||||
positionalArguments.append(
|
||||
{QString("entry"), QObject::tr("Path of the entry to clip.", "clip = copy to clipboard"), QString("")});
|
||||
optionalArguments.append(
|
||||
{QString("timeout"), QObject::tr("Timeout in seconds before clearing the clipboard."), QString("[timeout]")});
|
||||
}
|
||||
|
||||
Clip::~Clip()
|
||||
{
|
||||
}
|
||||
|
||||
int Clip::execute(const QStringList& arguments)
|
||||
int Clip::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption totp(QStringList() << "t"
|
||||
<< "totp",
|
||||
QObject::tr("Copy the current TOTP to the clipboard."));
|
||||
parser.addOption(totp);
|
||||
parser.addPositionalArgument("entry", QObject::tr("Path of the entry to clip.", "clip = copy to clipboard"));
|
||||
parser.addPositionalArgument(
|
||||
"timeout", QObject::tr("Timeout in seconds before clearing the clipboard."), "[timeout]");
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2 && args.size() != 3) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "clip [options]");
|
||||
return EXIT_FAILURE;
|
||||
const QStringList args = parser->positionalArguments();
|
||||
QString entryPath = args.at(1);
|
||||
QString timeout;
|
||||
if (args.size() == 3) {
|
||||
timeout = args.at(2);
|
||||
}
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return clipEntry(db, args.at(1), args.value(2), parser.isSet(totp), parser.isSet(Command::QuietOption));
|
||||
}
|
||||
|
||||
int Clip::clipEntry(const QSharedPointer<Database>& database,
|
||||
const QString& entryPath,
|
||||
const QString& timeout,
|
||||
bool clipTotp,
|
||||
bool silent)
|
||||
{
|
||||
bool clipTotp = parser->isSet(Clip::TotpOption);
|
||||
TextStream errorTextStream(Utils::STDERR);
|
||||
|
||||
int timeoutSeconds = 0;
|
||||
if (!timeout.isEmpty() && !timeout.toInt()) {
|
||||
if (!timeout.isEmpty() && timeout.toInt() <= 0) {
|
||||
errorTextStream << QObject::tr("Invalid timeout value %1.").arg(timeout) << endl;
|
||||
return EXIT_FAILURE;
|
||||
} else if (!timeout.isEmpty()) {
|
||||
timeoutSeconds = timeout.toInt();
|
||||
}
|
||||
|
||||
TextStream outputTextStream(silent ? Utils::DEVNULL : Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream outputTextStream(parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
QIODevice::WriteOnly);
|
||||
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||
if (!entry) {
|
||||
errorTextStream << QObject::tr("Entry %1 not found.").arg(entryPath) << endl;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,19 +18,17 @@
|
||||
#ifndef KEEPASSXC_CLIP_H
|
||||
#define KEEPASSXC_CLIP_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Clip : public Command
|
||||
class Clip : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Clip();
|
||||
~Clip();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int clipEntry(const QSharedPointer<Database>& database,
|
||||
const QString& entryPath,
|
||||
const QString& timeout,
|
||||
bool clipTotp,
|
||||
bool silent);
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption TotpOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_CLIP_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -35,6 +35,8 @@
|
||||
#include "Merge.h"
|
||||
#include "Remove.h"
|
||||
#include "Show.h"
|
||||
#include "TextStream.h"
|
||||
#include "Utils.h"
|
||||
|
||||
const QCommandLineOption Command::QuietOption =
|
||||
QCommandLineOption(QStringList() << "q"
|
||||
@ -51,13 +53,17 @@ const QCommandLineOption Command::NoPasswordOption =
|
||||
|
||||
QMap<QString, Command*> commands;
|
||||
|
||||
Command::Command()
|
||||
{
|
||||
options.append(Command::QuietOption);
|
||||
}
|
||||
|
||||
Command::~Command()
|
||||
{
|
||||
}
|
||||
|
||||
QString Command::getDescriptionLine()
|
||||
{
|
||||
|
||||
QString response = name;
|
||||
QString space(" ");
|
||||
QString spaces = space.repeated(15 - name.length());
|
||||
@ -67,6 +73,36 @@ QString Command::getDescriptionLine()
|
||||
return response;
|
||||
}
|
||||
|
||||
QSharedPointer<QCommandLineParser> Command::getCommandLineParser(const QStringList& arguments)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QSharedPointer<QCommandLineParser> parser = QSharedPointer<QCommandLineParser>(new QCommandLineParser());
|
||||
parser->setApplicationDescription(description);
|
||||
for (CommandLineArgument positionalArgument : positionalArguments) {
|
||||
parser->addPositionalArgument(
|
||||
positionalArgument.name, positionalArgument.description, positionalArgument.syntax);
|
||||
}
|
||||
for (CommandLineArgument optionalArgument : optionalArguments) {
|
||||
parser->addPositionalArgument(optionalArgument.name, optionalArgument.description, optionalArgument.syntax);
|
||||
}
|
||||
for (QCommandLineOption option : options) {
|
||||
parser->addOption(option);
|
||||
}
|
||||
parser->addHelpOption();
|
||||
parser->process(arguments);
|
||||
|
||||
if (parser->positionalArguments().size() < positionalArguments.size()) {
|
||||
errorTextStream << parser->helpText().replace("[options]", name.append(" [options]"));
|
||||
return QSharedPointer<QCommandLineParser>(nullptr);
|
||||
}
|
||||
if (parser->positionalArguments().size() > (positionalArguments.size() + optionalArguments.size())) {
|
||||
errorTextStream << parser->helpText().replace("[options]", name.append(" [options]"));
|
||||
return QSharedPointer<QCommandLineParser>(nullptr);
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
void populateCommands()
|
||||
{
|
||||
if (commands.isEmpty()) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -19,6 +19,7 @@
|
||||
#define KEEPASSXC_COMMAND_H
|
||||
|
||||
#include <QCommandLineOption>
|
||||
#include <QCommandLineParser>
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
@ -26,14 +27,28 @@
|
||||
|
||||
#include "core/Database.h"
|
||||
|
||||
// At the moment, there's no QT class for the positional arguments
|
||||
// like there is for the options (QCommandLineOption).
|
||||
struct CommandLineArgument
|
||||
{
|
||||
QString name;
|
||||
QString description;
|
||||
QString syntax;
|
||||
};
|
||||
|
||||
class Command
|
||||
{
|
||||
public:
|
||||
Command();
|
||||
virtual ~Command();
|
||||
virtual int execute(const QStringList& arguments) = 0;
|
||||
QString name;
|
||||
QString description;
|
||||
QList<CommandLineArgument> positionalArguments;
|
||||
QList<CommandLineArgument> optionalArguments;
|
||||
QList<QCommandLineOption> options;
|
||||
QString getDescriptionLine();
|
||||
QSharedPointer<QCommandLineParser> getCommandLineParser(const QStringList& arguments);
|
||||
|
||||
static QList<Command*> getCommands();
|
||||
static Command* getCommand(const QString& commandName);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,7 +18,6 @@
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
@ -35,6 +34,8 @@ Create::Create()
|
||||
{
|
||||
name = QString("create");
|
||||
description = QObject::tr("Create a new database.");
|
||||
positionalArguments.append({QString("database"), QObject::tr("Path of the database."), QString("")});
|
||||
options.append(Command::KeyFileOption);
|
||||
}
|
||||
|
||||
Create::~Create()
|
||||
@ -59,21 +60,13 @@ int Create::execute(const QStringList& arguments)
|
||||
QTextStream out(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
QTextStream err(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() < 1) {
|
||||
out << parser.helpText().replace("[options]", "create [options]");
|
||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||
if (parser.isNull()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
|
||||
const QString& databaseFilename = args.at(0);
|
||||
if (QFileInfo::exists(databaseFilename)) {
|
||||
err << QObject::tr("File %1 already exists.").arg(databaseFilename) << endl;
|
||||
@ -88,8 +81,8 @@ int Create::execute(const QStringList& arguments)
|
||||
}
|
||||
|
||||
QSharedPointer<FileKey> fileKey;
|
||||
if (parser.isSet(Command::KeyFileOption)) {
|
||||
if (!loadFileKey(parser.value(Command::KeyFileOption), fileKey)) {
|
||||
if (parser->isSet(Command::KeyFileOption)) {
|
||||
if (!loadFileKey(parser->value(Command::KeyFileOption), fileKey)) {
|
||||
err << QObject::tr("Loading the key file failed") << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
47
src/cli/DatabaseCommand.cpp
Normal file
47
src/cli/DatabaseCommand.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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 "DatabaseCommand.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
DatabaseCommand::DatabaseCommand()
|
||||
{
|
||||
positionalArguments.append({QString("database"), QObject::tr("Path of the database."), QString("")});
|
||||
options.append(Command::KeyFileOption);
|
||||
options.append(Command::NoPasswordOption);
|
||||
}
|
||||
|
||||
int DatabaseCommand::execute(const QStringList& arguments)
|
||||
{
|
||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||
if (parser.isNull()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser->isSet(Command::NoPasswordOption),
|
||||
parser->value(Command::KeyFileOption),
|
||||
parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return executeWithDatabase(db, parser);
|
||||
}
|
35
src/cli/DatabaseCommand.h
Normal file
35
src/cli/DatabaseCommand.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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_DATABASECOMMAND_H
|
||||
#define KEEPASSXC_DATABASECOMMAND_H
|
||||
|
||||
#include <QCommandLineOption>
|
||||
|
||||
#include "Command.h"
|
||||
#include "Utils.h"
|
||||
#include "core/Database.h"
|
||||
|
||||
class DatabaseCommand : public Command
|
||||
{
|
||||
public:
|
||||
DatabaseCommand();
|
||||
int execute(const QStringList& arguments) override;
|
||||
virtual int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser) = 0;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_DATABASECOMMAND_H
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,16 +20,28 @@
|
||||
|
||||
#include "Diceware.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "Utils.h"
|
||||
#include "cli/TextStream.h"
|
||||
#include "core/PassphraseGenerator.h"
|
||||
|
||||
const QCommandLineOption Diceware::WordCountOption =
|
||||
QCommandLineOption(QStringList() << "W"
|
||||
<< "words",
|
||||
QObject::tr("Word count for the diceware passphrase."),
|
||||
QObject::tr("count", "CLI parameter"));
|
||||
|
||||
const QCommandLineOption Diceware::WordListOption =
|
||||
QCommandLineOption(QStringList() << "w"
|
||||
<< "word-list",
|
||||
QObject::tr("Wordlist for the diceware generator.\n[Default: EFF English]"),
|
||||
QObject::tr("path"));
|
||||
|
||||
Diceware::Diceware()
|
||||
{
|
||||
name = QString("diceware");
|
||||
description = QObject::tr("Generate a new random diceware passphrase.");
|
||||
options.append(Diceware::WordCountOption);
|
||||
options.append(Diceware::WordListOption);
|
||||
}
|
||||
|
||||
Diceware::~Diceware()
|
||||
@ -38,45 +50,35 @@ Diceware::~Diceware()
|
||||
|
||||
int Diceware::execute(const QStringList& arguments)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
QCommandLineOption words(QStringList() << "W"
|
||||
<< "words",
|
||||
QObject::tr("Word count for the diceware passphrase."),
|
||||
QObject::tr("count", "CLI parameter"));
|
||||
parser.addOption(words);
|
||||
QCommandLineOption wordlistFile(QStringList() << "w"
|
||||
<< "word-list",
|
||||
QObject::tr("Wordlist for the diceware generator.\n[Default: EFF English]"),
|
||||
QObject::tr("path"));
|
||||
parser.addOption(wordlistFile);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (!args.isEmpty()) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "diceware [options]");
|
||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||
if (parser.isNull()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
PassphraseGenerator dicewareGenerator;
|
||||
|
||||
if (parser.value(words).isEmpty()) {
|
||||
QString wordCount = parser->value(Diceware::WordCountOption);
|
||||
if (wordCount.isEmpty()) {
|
||||
dicewareGenerator.setWordCount(PassphraseGenerator::DefaultWordCount);
|
||||
} else if (wordCount.toInt() <= 0) {
|
||||
errorTextStream << QObject::tr("Invalid word count %1").arg(wordCount) << endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
int wordcount = parser.value(words).toInt();
|
||||
dicewareGenerator.setWordCount(wordcount);
|
||||
dicewareGenerator.setWordCount(wordCount.toInt());
|
||||
}
|
||||
|
||||
if (!parser.value(wordlistFile).isEmpty()) {
|
||||
dicewareGenerator.setWordList(parser.value(wordlistFile));
|
||||
QString wordListFile = parser->value(Diceware::WordListOption);
|
||||
if (!wordListFile.isEmpty()) {
|
||||
dicewareGenerator.setWordList(wordListFile);
|
||||
}
|
||||
|
||||
if (!dicewareGenerator.isValid()) {
|
||||
outputTextStream << parser.helpText().replace("[options]", "diceware [options]");
|
||||
// We already validated the word count input so if the generator is invalid, it
|
||||
// must be because the word list is too small.
|
||||
errorTextStream << QObject::tr("The word list is too small (< 1000 items)") << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -25,7 +25,11 @@ class Diceware : public Command
|
||||
public:
|
||||
Diceware();
|
||||
~Diceware();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
int execute(const QStringList& arguments);
|
||||
|
||||
static const QCommandLineOption WordCountOption;
|
||||
static const QCommandLineOption WordListOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_DICEWARE_H
|
||||
|
121
src/cli/Edit.cpp
121
src/cli/Edit.cpp
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,8 +20,7 @@
|
||||
|
||||
#include "Edit.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/Add.h"
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
@ -29,120 +28,80 @@
|
||||
#include "core/Group.h"
|
||||
#include "core/PasswordGenerator.h"
|
||||
|
||||
const QCommandLineOption Edit::TitleOption = QCommandLineOption(QStringList() << "t"
|
||||
<< "title",
|
||||
QObject::tr("Title for the entry."),
|
||||
QObject::tr("title"));
|
||||
|
||||
Edit::Edit()
|
||||
{
|
||||
name = QString("edit");
|
||||
description = QObject::tr("Edit an entry.");
|
||||
// Using some of the options from the Add command since they are the same.
|
||||
options.append(Add::UsernameOption);
|
||||
options.append(Add::UrlOption);
|
||||
options.append(Add::PasswordPromptOption);
|
||||
options.append(Add::GenerateOption);
|
||||
options.append(Add::PasswordLengthOption);
|
||||
options.append(Edit::TitleOption);
|
||||
positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to edit."), QString("")});
|
||||
}
|
||||
|
||||
Edit::~Edit()
|
||||
{
|
||||
}
|
||||
|
||||
int Edit::execute(const QStringList& arguments)
|
||||
int Edit::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream outputTextStream(parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption username(QStringList() << "u"
|
||||
<< "username",
|
||||
QObject::tr("Username for the entry."),
|
||||
QObject::tr("username"));
|
||||
parser.addOption(username);
|
||||
|
||||
QCommandLineOption url(QStringList() << "url", QObject::tr("URL for the entry."), QObject::tr("URL"));
|
||||
parser.addOption(url);
|
||||
|
||||
QCommandLineOption title(QStringList() << "t"
|
||||
<< "title",
|
||||
QObject::tr("Title for the entry."),
|
||||
QObject::tr("title"));
|
||||
parser.addOption(title);
|
||||
|
||||
QCommandLineOption prompt(QStringList() << "p"
|
||||
<< "password-prompt",
|
||||
QObject::tr("Prompt for the entry's password."));
|
||||
parser.addOption(prompt);
|
||||
|
||||
QCommandLineOption generate(QStringList() << "g"
|
||||
<< "generate",
|
||||
QObject::tr("Generate a password for the entry."));
|
||||
parser.addOption(generate);
|
||||
|
||||
QCommandLineOption length(QStringList() << "l"
|
||||
<< "password-length",
|
||||
QObject::tr("Length for the generated password."),
|
||||
QObject::tr("length"));
|
||||
parser.addOption(length);
|
||||
|
||||
parser.addPositionalArgument("entry", QObject::tr("Path of the entry to edit."));
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "edit [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
const QString& databasePath = args.at(0);
|
||||
const QString& entryPath = args.at(1);
|
||||
|
||||
auto db = Utils::unlockDatabase(databasePath,
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QString passwordLength = parser.value(length);
|
||||
QString passwordLength = parser->value(Add::PasswordLengthOption);
|
||||
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
||||
errorTextStream << QObject::tr("Invalid value for password length: %1").arg(passwordLength) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Entry* entry = db->rootGroup()->findEntryByPath(entryPath);
|
||||
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||
if (!entry) {
|
||||
errorTextStream << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (parser.value("username").isEmpty() && parser.value("url").isEmpty() && parser.value("title").isEmpty()
|
||||
&& !parser.isSet(prompt) && !parser.isSet(generate)) {
|
||||
QString username = parser->value(Add::UsernameOption);
|
||||
QString url = parser->value(Add::UrlOption);
|
||||
QString title = parser->value(Edit::TitleOption);
|
||||
bool generate = parser->isSet(Add::GenerateOption);
|
||||
bool prompt = parser->isSet(Add::PasswordPromptOption);
|
||||
if (username.isEmpty() && url.isEmpty() && title.isEmpty() && !prompt && !generate) {
|
||||
errorTextStream << QObject::tr("Not changing any field for entry %1.").arg(entryPath) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
entry->beginUpdate();
|
||||
|
||||
if (!parser.value("title").isEmpty()) {
|
||||
entry->setTitle(parser.value("title"));
|
||||
if (!title.isEmpty()) {
|
||||
entry->setTitle(title);
|
||||
}
|
||||
|
||||
if (!parser.value("username").isEmpty()) {
|
||||
entry->setUsername(parser.value("username"));
|
||||
if (!username.isEmpty()) {
|
||||
entry->setUsername(username);
|
||||
}
|
||||
|
||||
if (!parser.value("url").isEmpty()) {
|
||||
entry->setUrl(parser.value("url"));
|
||||
if (!url.isEmpty()) {
|
||||
entry->setUrl(url);
|
||||
}
|
||||
|
||||
if (parser.isSet(prompt)) {
|
||||
if (!parser.isSet(Command::QuietOption)) {
|
||||
outputTextStream << QObject::tr("Enter new password for entry: ") << flush;
|
||||
}
|
||||
QString password = Utils::getPassword(parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||
if (prompt) {
|
||||
outputTextStream << QObject::tr("Enter new password for entry: ") << flush;
|
||||
QString password = Utils::getPassword(parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT);
|
||||
entry->setPassword(password);
|
||||
} else if (parser.isSet(generate)) {
|
||||
} else if (generate) {
|
||||
PasswordGenerator passwordGenerator;
|
||||
|
||||
if (passwordLength.isEmpty()) {
|
||||
@ -160,13 +119,11 @@ int Edit::execute(const QStringList& arguments)
|
||||
entry->endUpdate();
|
||||
|
||||
QString errorMessage;
|
||||
if (!db->save(databasePath, &errorMessage, true, false)) {
|
||||
if (!database->save(databasePath, &errorMessage, true, false)) {
|
||||
errorTextStream << QObject::tr("Writing the database failed: %1").arg(errorMessage) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!parser.isSet(Command::QuietOption)) {
|
||||
outputTextStream << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << endl;
|
||||
}
|
||||
outputTextStream << QObject::tr("Successfully edited entry %1.").arg(entry->title()) << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,14 +18,16 @@
|
||||
#ifndef KEEPASSXC_EDIT_H
|
||||
#define KEEPASSXC_EDIT_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Edit : public Command
|
||||
class Edit : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Edit();
|
||||
~Edit();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption TitleOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_EDIT_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,8 +18,6 @@
|
||||
#include "Estimate.h"
|
||||
#include "cli/Utils.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -33,9 +31,17 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const QCommandLineOption Estimate::AdvancedOption =
|
||||
QCommandLineOption(QStringList() << "a"
|
||||
<< "advanced",
|
||||
QObject::tr("Perform advanced analysis on the password."));
|
||||
|
||||
Estimate::Estimate()
|
||||
{
|
||||
name = QString("estimate");
|
||||
optionalArguments.append(
|
||||
{QString("password"), QObject::tr("Password for which to estimate the entropy."), QString("[password]")});
|
||||
options.append(Estimate::AdvancedOption);
|
||||
description = QObject::tr("Estimate the entropy of a password.");
|
||||
}
|
||||
|
||||
@ -156,25 +162,14 @@ static void estimate(const char* pwd, bool advanced)
|
||||
|
||||
int Estimate::execute(const QStringList& arguments)
|
||||
{
|
||||
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("password", QObject::tr("Password for which to estimate the entropy."), "[password]");
|
||||
QCommandLineOption advancedOption(QStringList() << "a"
|
||||
<< "advanced",
|
||||
QObject::tr("Perform advanced analysis on the password."));
|
||||
parser.addOption(advancedOption);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() > 1) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "estimate [options]");
|
||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||
if (parser.isNull()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
||||
const QStringList args = parser->positionalArguments();
|
||||
|
||||
QString password;
|
||||
if (args.size() == 1) {
|
||||
password = args.at(0);
|
||||
@ -182,6 +177,6 @@ int Estimate::execute(const QStringList& arguments)
|
||||
password = inputTextStream.readLine();
|
||||
}
|
||||
|
||||
estimate(password.toLatin1(), parser.isSet(advancedOption));
|
||||
estimate(password.toLatin1(), parser->isSet(Estimate::AdvancedOption));
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -26,6 +26,8 @@ public:
|
||||
Estimate();
|
||||
~Estimate();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
static const QCommandLineOption AdvancedOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_ESTIMATE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,9 +20,6 @@
|
||||
|
||||
#include "Extract.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QFile>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
@ -37,40 +34,14 @@ Extract::~Extract()
|
||||
{
|
||||
}
|
||||
|
||||
int Extract::execute(const QStringList& arguments)
|
||||
int Extract::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser>)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database to extract."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 1) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "extract [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto compositeKey = QSharedPointer<CompositeKey>::create();
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
QByteArray xmlData;
|
||||
QString errorMessage;
|
||||
if (!db->extract(xmlData, &errorMessage)) {
|
||||
if (!database->extract(xmlData, &errorMessage)) {
|
||||
errorTextStream << QObject::tr("Unable to extract database %1").arg(errorMessage) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,14 +18,15 @@
|
||||
#ifndef KEEPASSXC_EXTRACT_H
|
||||
#define KEEPASSXC_EXTRACT_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Extract : public Command
|
||||
class Extract : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Extract();
|
||||
~Extract();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_EXTRACT_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -19,17 +19,60 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Generate.h"
|
||||
#include "cli/Utils.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/PasswordGenerator.h"
|
||||
|
||||
const QCommandLineOption Generate::PasswordLengthOption =
|
||||
QCommandLineOption(QStringList() << "L"
|
||||
<< "length",
|
||||
QObject::tr("Length of the generated password"),
|
||||
QObject::tr("length"));
|
||||
|
||||
const QCommandLineOption Generate::LowerCaseOption = QCommandLineOption(QStringList() << "l"
|
||||
<< "lower",
|
||||
QObject::tr("Use lowercase characters"));
|
||||
|
||||
const QCommandLineOption Generate::UpperCaseOption = QCommandLineOption(QStringList() << "u"
|
||||
<< "upper",
|
||||
QObject::tr("Use uppercase characters"));
|
||||
|
||||
const QCommandLineOption Generate::NumbersOption = QCommandLineOption(QStringList() << "n"
|
||||
<< "numeric",
|
||||
QObject::tr("Use numbers"));
|
||||
|
||||
const QCommandLineOption Generate::SpecialCharsOption = QCommandLineOption(QStringList() << "s"
|
||||
<< "special",
|
||||
QObject::tr("Use special characters"));
|
||||
|
||||
const QCommandLineOption Generate::ExtendedAsciiOption = QCommandLineOption(QStringList() << "e"
|
||||
<< "extended",
|
||||
QObject::tr("Use extended ASCII"));
|
||||
|
||||
const QCommandLineOption Generate::ExcludeCharsOption = QCommandLineOption(QStringList() << "x"
|
||||
<< "exclude",
|
||||
QObject::tr("Exclude character set"),
|
||||
QObject::tr("chars"));
|
||||
|
||||
const QCommandLineOption Generate::ExcludeSimilarCharsOption =
|
||||
QCommandLineOption(QStringList() << "exclude-similar", QObject::tr("Exclude similar looking characters"));
|
||||
|
||||
const QCommandLineOption Generate::IncludeEveryGroupOption =
|
||||
QCommandLineOption(QStringList() << "every-group", QObject::tr("Include characters from every selected group"));
|
||||
Generate::Generate()
|
||||
{
|
||||
name = QString("generate");
|
||||
description = QObject::tr("Generate a new random password.");
|
||||
options.append(Generate::PasswordLengthOption);
|
||||
options.append(Generate::LowerCaseOption);
|
||||
options.append(Generate::UpperCaseOption);
|
||||
options.append(Generate::NumbersOption);
|
||||
options.append(Generate::SpecialCharsOption);
|
||||
options.append(Generate::ExtendedAsciiOption);
|
||||
options.append(Generate::ExcludeCharsOption);
|
||||
options.append(Generate::ExcludeSimilarCharsOption);
|
||||
options.append(Generate::IncludeEveryGroupOption);
|
||||
}
|
||||
|
||||
Generate::~Generate()
|
||||
@ -38,97 +81,59 @@ Generate::~Generate()
|
||||
|
||||
int Generate::execute(const QStringList& arguments)
|
||||
{
|
||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||
if (parser.isNull()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
QCommandLineOption len(QStringList() << "L"
|
||||
<< "length",
|
||||
QObject::tr("Length of the generated password"),
|
||||
QObject::tr("length"));
|
||||
parser.addOption(len);
|
||||
QCommandLineOption lower(QStringList() << "l"
|
||||
<< "lower",
|
||||
QObject::tr("Use lowercase characters"));
|
||||
parser.addOption(lower);
|
||||
QCommandLineOption upper(QStringList() << "u"
|
||||
<< "upper",
|
||||
QObject::tr("Use uppercase characters"));
|
||||
parser.addOption(upper);
|
||||
QCommandLineOption numeric(QStringList() << "n"
|
||||
<< "numeric",
|
||||
QObject::tr("Use numbers."));
|
||||
parser.addOption(numeric);
|
||||
QCommandLineOption special(QStringList() << "s"
|
||||
<< "special",
|
||||
QObject::tr("Use special characters"));
|
||||
parser.addOption(special);
|
||||
QCommandLineOption extended(QStringList() << "e"
|
||||
<< "extended",
|
||||
QObject::tr("Use extended ASCII"));
|
||||
parser.addOption(extended);
|
||||
QCommandLineOption exclude(QStringList() << "x"
|
||||
<< "exclude",
|
||||
QObject::tr("Exclude character set"),
|
||||
QObject::tr("chars"));
|
||||
parser.addOption(exclude);
|
||||
QCommandLineOption exclude_similar(QStringList() << "exclude-similar",
|
||||
QObject::tr("Exclude similar looking characters"));
|
||||
parser.addOption(exclude_similar);
|
||||
QCommandLineOption every_group(QStringList() << "every-group",
|
||||
QObject::tr("Include characters from every selected group"));
|
||||
parser.addOption(every_group);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (!args.isEmpty()) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "generate [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const QStringList args = parser->positionalArguments();
|
||||
|
||||
PasswordGenerator passwordGenerator;
|
||||
|
||||
if (parser.value(len).isEmpty()) {
|
||||
QString passwordLength = parser->value(Generate::PasswordLengthOption);
|
||||
if (passwordLength.isEmpty()) {
|
||||
passwordGenerator.setLength(PasswordGenerator::DefaultLength);
|
||||
} else if (passwordLength.toInt() <= 0) {
|
||||
errorTextStream << QObject::tr("Invalid password length %1").arg(passwordLength) << endl;
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
passwordGenerator.setLength(parser.value(len).toInt());
|
||||
passwordGenerator.setLength(passwordLength.toInt());
|
||||
}
|
||||
|
||||
PasswordGenerator::CharClasses classes = 0x0;
|
||||
|
||||
if (parser.isSet(lower)) {
|
||||
if (parser->isSet(Generate::LowerCaseOption)) {
|
||||
classes |= PasswordGenerator::LowerLetters;
|
||||
}
|
||||
if (parser.isSet(upper)) {
|
||||
if (parser->isSet(Generate::UpperCaseOption)) {
|
||||
classes |= PasswordGenerator::UpperLetters;
|
||||
}
|
||||
if (parser.isSet(numeric)) {
|
||||
if (parser->isSet(Generate::NumbersOption)) {
|
||||
classes |= PasswordGenerator::Numbers;
|
||||
}
|
||||
if (parser.isSet(special)) {
|
||||
if (parser->isSet(Generate::SpecialCharsOption)) {
|
||||
classes |= PasswordGenerator::SpecialCharacters;
|
||||
}
|
||||
if (parser.isSet(extended)) {
|
||||
if (parser->isSet(Generate::ExtendedAsciiOption)) {
|
||||
classes |= PasswordGenerator::EASCII;
|
||||
}
|
||||
|
||||
PasswordGenerator::GeneratorFlags flags = 0x0;
|
||||
|
||||
if (parser.isSet(exclude_similar)) {
|
||||
if (parser->isSet(Generate::ExcludeSimilarCharsOption)) {
|
||||
flags |= PasswordGenerator::ExcludeLookAlike;
|
||||
}
|
||||
if (parser.isSet(every_group)) {
|
||||
if (parser->isSet(Generate::IncludeEveryGroupOption)) {
|
||||
flags |= PasswordGenerator::CharFromEveryGroup;
|
||||
}
|
||||
|
||||
passwordGenerator.setCharClasses(classes);
|
||||
passwordGenerator.setFlags(flags);
|
||||
passwordGenerator.setExcludedChars(parser.value(exclude));
|
||||
passwordGenerator.setExcludedChars(parser->value(Generate::ExcludeCharsOption));
|
||||
|
||||
if (!passwordGenerator.isValid()) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "generate [options]");
|
||||
errorTextStream << QObject::tr("invalid password generator after applying all options") << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -26,6 +26,16 @@ public:
|
||||
Generate();
|
||||
~Generate();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
static const QCommandLineOption PasswordLengthOption;
|
||||
static const QCommandLineOption LowerCaseOption;
|
||||
static const QCommandLineOption UpperCaseOption;
|
||||
static const QCommandLineOption NumbersOption;
|
||||
static const QCommandLineOption SpecialCharsOption;
|
||||
static const QCommandLineOption ExtendedAsciiOption;
|
||||
static const QCommandLineOption ExcludeCharsOption;
|
||||
static const QCommandLineOption ExcludeSimilarCharsOption;
|
||||
static const QCommandLineOption IncludeEveryGroupOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_GENERATE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -21,75 +21,44 @@
|
||||
#include "List.h"
|
||||
#include "cli/Utils.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
|
||||
const QCommandLineOption List::RecursiveOption =
|
||||
QCommandLineOption(QStringList() << "R"
|
||||
<< "recursive",
|
||||
QObject::tr("Recursively list the elements of the group."));
|
||||
|
||||
List::List()
|
||||
{
|
||||
name = QString("ls");
|
||||
description = QObject::tr("List database entries.");
|
||||
options.append(List::RecursiveOption);
|
||||
optionalArguments.append(
|
||||
{QString("group"), QObject::tr("Path of the group to list. Default is /"), QString("[group]")});
|
||||
}
|
||||
|
||||
List::~List()
|
||||
{
|
||||
}
|
||||
|
||||
int List::execute(const QStringList& arguments)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addPositionalArgument("group", QObject::tr("Path of the group to list. Default is /"), "[group]");
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption recursiveOption(QStringList() << "R"
|
||||
<< "recursive",
|
||||
QObject::tr("Recursively list the elements of the group."));
|
||||
parser.addOption(recursiveOption);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 1 && args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "ls [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool recursive = parser.isSet(recursiveOption);
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (args.size() == 2) {
|
||||
return listGroup(db.data(), recursive, args.at(1));
|
||||
}
|
||||
return listGroup(db.data(), recursive);
|
||||
}
|
||||
|
||||
int List::listGroup(Database* database, bool recursive, const QString& groupPath)
|
||||
int List::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
if (groupPath.isEmpty()) {
|
||||
const QStringList args = parser->positionalArguments();
|
||||
bool recursive = parser->isSet(List::RecursiveOption);
|
||||
|
||||
// No group provided, defaulting to root group.
|
||||
if (args.size() == 1) {
|
||||
outputTextStream << database->rootGroup()->print(recursive) << flush;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
QString groupPath = args.at(1);
|
||||
Group* group = database->rootGroup()->findGroupByPath(groupPath);
|
||||
if (!group) {
|
||||
errorTextStream << QObject::tr("Cannot find group %1.").arg(groupPath) << endl;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,15 +18,17 @@
|
||||
#ifndef KEEPASSXC_LIST_H
|
||||
#define KEEPASSXC_LIST_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class List : public Command
|
||||
class List : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
List();
|
||||
~List();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int listGroup(Database* database, bool recursive, const QString& groupPath = {});
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption RecursiveOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_LIST_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,7 +20,6 @@
|
||||
|
||||
#include "Locate.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QStringList>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
@ -34,46 +33,18 @@ Locate::Locate()
|
||||
{
|
||||
name = QString("locate");
|
||||
description = QObject::tr("Find entries quickly.");
|
||||
positionalArguments.append({QString("term"), QObject::tr("Search term."), QString("")});
|
||||
}
|
||||
|
||||
Locate::~Locate()
|
||||
{
|
||||
}
|
||||
|
||||
int Locate::execute(const QStringList& arguments)
|
||||
int Locate::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addPositionalArgument("term", QObject::tr("Search term."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "locate [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return locateEntry(db.data(), args.at(1));
|
||||
}
|
||||
|
||||
int Locate::locateEntry(Database* database, const QString& searchTerm)
|
||||
{
|
||||
const QStringList args = parser->positionalArguments();
|
||||
QString searchTerm = args.at(1);
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,15 +18,15 @@
|
||||
#ifndef KEEPASSXC_LOCATE_H
|
||||
#define KEEPASSXC_LOCATE_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Locate : public Command
|
||||
class Locate : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Locate();
|
||||
~Locate();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int locateEntry(Database* database, const QString& searchTerm);
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_LOCATE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -15,79 +15,57 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Merge.h"
|
||||
#include <cstdlib>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include "Merge.h"
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
#include "core/Merger.h"
|
||||
|
||||
#include <cstdlib>
|
||||
const QCommandLineOption Merge::SameCredentialsOption =
|
||||
QCommandLineOption(QStringList() << "s"
|
||||
<< "same-credentials",
|
||||
QObject::tr("Use the same credentials for both database files."));
|
||||
|
||||
const QCommandLineOption Merge::KeyFileFromOption =
|
||||
QCommandLineOption(QStringList() << "k"
|
||||
<< "key-file-from",
|
||||
QObject::tr("Key file of the database to merge from."),
|
||||
QObject::tr("path"));
|
||||
|
||||
const QCommandLineOption Merge::NoPasswordFromOption =
|
||||
QCommandLineOption(QStringList() << "no-password-from",
|
||||
QObject::tr("Deactivate password key for the database to merge from."));
|
||||
|
||||
Merge::Merge()
|
||||
{
|
||||
name = QString("merge");
|
||||
description = QObject::tr("Merge two databases.");
|
||||
options.append(Merge::SameCredentialsOption);
|
||||
options.append(Merge::KeyFileFromOption);
|
||||
options.append(Merge::NoPasswordFromOption);
|
||||
positionalArguments.append({QString("database2"), QObject::tr("Path of the database to merge from."), QString("")});
|
||||
}
|
||||
|
||||
Merge::~Merge()
|
||||
{
|
||||
}
|
||||
|
||||
int Merge::execute(const QStringList& arguments)
|
||||
int Merge::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
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.addOption(Command::QuietOption);
|
||||
|
||||
QCommandLineOption samePasswordOption(QStringList() << "s"
|
||||
<< "same-credentials",
|
||||
QObject::tr("Use the same credentials for both database files."));
|
||||
parser.addOption(samePasswordOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption keyFileFromOption(QStringList() << "f"
|
||||
<< "key-file-from",
|
||||
QObject::tr("Key file of the database to merge from."),
|
||||
QObject::tr("path"));
|
||||
parser.addOption(keyFileFromOption);
|
||||
|
||||
QCommandLineOption noPasswordFromOption(QStringList() << "no-password-from",
|
||||
QObject::tr("Deactivate password key for the database to merge from."));
|
||||
parser.addOption(noPasswordFromOption);
|
||||
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "merge [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto db1 = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db1) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
const QStringList args = parser->positionalArguments();
|
||||
|
||||
QSharedPointer<Database> db2;
|
||||
if (!parser.isSet("same-credentials")) {
|
||||
if (!parser->isSet(Merge::SameCredentialsOption)) {
|
||||
db2 = Utils::unlockDatabase(args.at(1),
|
||||
!parser.isSet(noPasswordFromOption),
|
||||
parser.value(keyFileFromOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
!parser->isSet(Merge::NoPasswordFromOption),
|
||||
parser->value(Merge::KeyFileFromOption),
|
||||
parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db2) {
|
||||
return EXIT_FAILURE;
|
||||
@ -95,25 +73,25 @@ int Merge::execute(const QStringList& arguments)
|
||||
} else {
|
||||
db2 = QSharedPointer<Database>::create();
|
||||
QString errorMessage;
|
||||
if (!db2->open(args.at(1), db1->key(), &errorMessage, false)) {
|
||||
if (!db2->open(args.at(1), database->key(), &errorMessage, false)) {
|
||||
errorTextStream << QObject::tr("Error reading merge file:\n%1").arg(errorMessage);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
Merger merger(db2.data(), db1.data());
|
||||
Merger merger(db2.data(), database.data());
|
||||
bool databaseChanged = merger.merge();
|
||||
|
||||
if (databaseChanged) {
|
||||
QString errorMessage;
|
||||
if (!db1->save(args.at(0), &errorMessage, true, false)) {
|
||||
if (!database->save(args.at(0), &errorMessage, true, false)) {
|
||||
errorTextStream << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!parser.isSet(Command::QuietOption)) {
|
||||
if (!parser->isSet(Command::QuietOption)) {
|
||||
outputTextStream << "Successfully merged the database files." << endl;
|
||||
}
|
||||
} else if (!parser.isSet(Command::QuietOption)) {
|
||||
} else if (!parser->isSet(Command::QuietOption)) {
|
||||
outputTextStream << "Database was not modified by merge operation." << endl;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,14 +18,19 @@
|
||||
#ifndef KEEPASSXC_MERGE_H
|
||||
#define KEEPASSXC_MERGE_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Merge : public Command
|
||||
class Merge : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Merge();
|
||||
~Merge();
|
||||
int execute(const QStringList& arguments) override;
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption SameCredentialsOption;
|
||||
static const QCommandLineOption KeyFileFromOption;
|
||||
static const QCommandLineOption NoPasswordFromOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_MERGE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,10 +20,6 @@
|
||||
|
||||
#include "Remove.h"
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QStringList>
|
||||
|
||||
#include "cli/TextStream.h"
|
||||
#include "cli/Utils.h"
|
||||
#include "core/Database.h"
|
||||
@ -36,46 +32,19 @@ Remove::Remove()
|
||||
{
|
||||
name = QString("rm");
|
||||
description = QString("Remove an entry from the database.");
|
||||
positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to remove."), QString("")});
|
||||
}
|
||||
|
||||
Remove::~Remove()
|
||||
{
|
||||
}
|
||||
|
||||
int Remove::execute(const QStringList& arguments)
|
||||
int Remove::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
bool quiet = parser->isSet(Command::QuietOption);
|
||||
QString databasePath = parser->positionalArguments().at(0);
|
||||
QString entryPath = parser->positionalArguments().at(1);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(QObject::tr("Remove an entry from the database."));
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
parser.addPositionalArgument("entry", QObject::tr("Path of the entry to remove."));
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "rm [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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, bool quiet)
|
||||
{
|
||||
TextStream outputTextStream(quiet ? Utils::DEVNULL : Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
|
@ -18,17 +18,15 @@
|
||||
#ifndef KEEPASSXC_REMOVE_H
|
||||
#define KEEPASSXC_REMOVE_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
#include "core/Database.h"
|
||||
|
||||
class Remove : public Command
|
||||
class Remove : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Remove();
|
||||
~Remove();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int removeEntry(Database* database, const QString& databasePath, const QString& entryPath, bool quiet);
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_REMOVE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -20,8 +20,6 @@
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
|
||||
#include "Utils.h"
|
||||
#include "cli/TextStream.h"
|
||||
#include "core/Database.h"
|
||||
@ -29,67 +27,42 @@
|
||||
#include "core/Global.h"
|
||||
#include "core/Group.h"
|
||||
|
||||
const QCommandLineOption Show::TotpOption = QCommandLineOption(QStringList() << "t"
|
||||
<< "totp",
|
||||
QObject::tr("Show the entry's current TOTP."));
|
||||
|
||||
const QCommandLineOption Show::AttributesOption = QCommandLineOption(
|
||||
QStringList() << "a"
|
||||
<< "attributes",
|
||||
QObject::tr(
|
||||
"Names of the attributes to show. "
|
||||
"This option can be specified more than once, with each attribute shown one-per-line in the given order. "
|
||||
"If no attributes are specified, a summary of the default attributes is given."),
|
||||
QObject::tr("attribute"));
|
||||
|
||||
Show::Show()
|
||||
{
|
||||
name = QString("show");
|
||||
description = QObject::tr("Show an entry's information.");
|
||||
options.append(Show::TotpOption);
|
||||
options.append(Show::AttributesOption);
|
||||
positionalArguments.append({QString("entry"), QObject::tr("Name of the entry to show."), QString("")});
|
||||
}
|
||||
|
||||
Show::~Show()
|
||||
{
|
||||
}
|
||||
|
||||
int Show::execute(const QStringList& arguments)
|
||||
{
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(description);
|
||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
||||
parser.addOption(Command::QuietOption);
|
||||
parser.addOption(Command::KeyFileOption);
|
||||
parser.addOption(Command::NoPasswordOption);
|
||||
|
||||
QCommandLineOption totp(QStringList() << "t"
|
||||
<< "totp",
|
||||
QObject::tr("Show the entry's current TOTP."));
|
||||
parser.addOption(totp);
|
||||
QCommandLineOption attributes(
|
||||
QStringList() << "a"
|
||||
<< "attributes",
|
||||
QObject::tr(
|
||||
"Names of the attributes to show. "
|
||||
"This option can be specified more than once, with each attribute shown one-per-line in the given order. "
|
||||
"If no attributes are specified, a summary of the default attributes is given."),
|
||||
QObject::tr("attribute"));
|
||||
parser.addOption(attributes);
|
||||
parser.addPositionalArgument("entry", QObject::tr("Name of the entry to show."));
|
||||
parser.addHelpOption();
|
||||
parser.process(arguments);
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if (args.size() != 2) {
|
||||
errorTextStream << parser.helpText().replace("[options]", "show [options]");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
auto db = Utils::unlockDatabase(args.at(0),
|
||||
!parser.isSet(Command::NoPasswordOption),
|
||||
parser.value(Command::KeyFileOption),
|
||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||
Utils::STDERR);
|
||||
if (!db) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return showEntry(db.data(), parser.values(attributes), parser.isSet(totp), args.at(1));
|
||||
}
|
||||
|
||||
int Show::showEntry(Database* database, QStringList attributes, bool showTotp, const QString& entryPath)
|
||||
int Show::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||
{
|
||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||
|
||||
const QStringList args = parser->positionalArguments();
|
||||
const QString& entryPath = args.at(1);
|
||||
bool showTotp = parser->isSet(Show::TotpOption);
|
||||
QStringList attributes = parser->values(Show::AttributesOption);
|
||||
|
||||
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||
if (!entry) {
|
||||
errorTextStream << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
|
||||
* Copyright (C) 2019 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
|
||||
@ -18,15 +18,18 @@
|
||||
#ifndef KEEPASSXC_SHOW_H
|
||||
#define KEEPASSXC_SHOW_H
|
||||
|
||||
#include "Command.h"
|
||||
#include "DatabaseCommand.h"
|
||||
|
||||
class Show : public Command
|
||||
class Show : public DatabaseCommand
|
||||
{
|
||||
public:
|
||||
Show();
|
||||
~Show();
|
||||
int execute(const QStringList& arguments) override;
|
||||
int showEntry(Database* database, QStringList attributes, bool showTotp, const QString& entryPath);
|
||||
|
||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||
|
||||
static const QCommandLineOption TotpOption;
|
||||
static const QCommandLineOption AttributesOption;
|
||||
};
|
||||
|
||||
#endif // KEEPASSXC_SHOW_H
|
||||
|
@ -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…
x
Reference in New Issue
Block a user