mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-04-27 19:06:19 -04:00
✨✨ CLI Command cleanup ✨✨
This PR cleans up the `Command` classes in the CLI, introducing a `DatabaseCommand` class for the commands operating on a database, and a `getCommandLineParser` command to centralize the arguments parsing and validation. The opening of the database based on the CLI arguments and options is now centralized in `DatabaseCommand.execute`, making it easy to add new database opening features (like YubiKey support for the CLI). Also a couple of bugs fixed: * `Create` was still using `stdout` for some error messages. * `Diceware` and `Generate` were not validating that the word count was an integer. * `Diceware` was also using `stdout` for some error messages.
This commit is contained in:
parent
3cf171cbf5
commit
04360ed552
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
#include "Add.h"
|
#include "Add.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
@ -29,106 +27,84 @@
|
|||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "core/PasswordGenerator.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()
|
Add::Add()
|
||||||
{
|
{
|
||||||
name = QString("add");
|
name = QString("add");
|
||||||
description = QObject::tr("Add a new entry to a database.");
|
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()
|
Add::~Add()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int Add::execute(const QStringList& arguments)
|
int Add::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||||
{
|
{
|
||||||
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
const QStringList args = parser->positionalArguments();
|
||||||
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 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 = 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
|
// Validating the password length here, before we actually create
|
||||||
// the entry.
|
// the entry.
|
||||||
QString passwordLength = parser.value(length);
|
QString passwordLength = parser->value(Add::PasswordLengthOption);
|
||||||
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
||||||
errorTextStream << QObject::tr("Invalid value for password length %1.").arg(passwordLength) << endl;
|
errorTextStream << QObject::tr("Invalid value for password length %1.").arg(passwordLength) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* entry = db->rootGroup()->addEntryWithPath(entryPath);
|
Entry* entry = database->rootGroup()->addEntryWithPath(entryPath);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
errorTextStream << QObject::tr("Could not create entry with path %1.").arg(entryPath) << endl;
|
errorTextStream << QObject::tr("Could not create entry with path %1.").arg(entryPath) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.value("username").isEmpty()) {
|
if (!parser->value(Add::UsernameOption).isEmpty()) {
|
||||||
entry->setUsername(parser.value("username"));
|
entry->setUsername(parser->value(Add::UsernameOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.value("url").isEmpty()) {
|
if (!parser->value(Add::UrlOption).isEmpty()) {
|
||||||
entry->setUrl(parser.value("url"));
|
entry->setUrl(parser->value(Add::UrlOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(prompt)) {
|
if (parser->isSet(Add::PasswordPromptOption)) {
|
||||||
if (!parser.isSet(Command::QuietOption)) {
|
if (!parser->isSet(Command::QuietOption)) {
|
||||||
outputTextStream << QObject::tr("Enter password for new entry: ") << flush;
|
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);
|
entry->setPassword(password);
|
||||||
} else if (parser.isSet(generate)) {
|
} else if (parser->isSet(Add::GenerateOption)) {
|
||||||
PasswordGenerator passwordGenerator;
|
PasswordGenerator passwordGenerator;
|
||||||
|
|
||||||
if (passwordLength.isEmpty()) {
|
if (passwordLength.isEmpty()) {
|
||||||
@ -144,12 +120,12 @@ int Add::execute(const QStringList& arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString errorMessage;
|
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;
|
errorTextStream << QObject::tr("Writing the database failed %1.").arg(errorMessage) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.isSet(Command::QuietOption)) {
|
if (!parser->isSet(Command::QuietOption)) {
|
||||||
outputTextStream << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl;
|
outputTextStream << QObject::tr("Successfully added entry %1.").arg(entry->title()) << endl;
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,14 +18,21 @@
|
|||||||
#ifndef KEEPASSXC_ADD_H
|
#ifndef KEEPASSXC_ADD_H
|
||||||
#define KEEPASSXC_ADD_H
|
#define KEEPASSXC_ADD_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Add : public Command
|
class Add : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Add();
|
Add();
|
||||||
~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
|
#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
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -18,6 +18,7 @@ set(cli_SOURCES
|
|||||||
Clip.cpp
|
Clip.cpp
|
||||||
Create.cpp
|
Create.cpp
|
||||||
Command.cpp
|
Command.cpp
|
||||||
|
DatabaseCommand.cpp
|
||||||
Diceware.cpp
|
Diceware.cpp
|
||||||
Edit.cpp
|
Edit.cpp
|
||||||
Estimate.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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -22,80 +22,52 @@
|
|||||||
|
|
||||||
#include "Clip.h"
|
#include "Clip.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Entry.h"
|
#include "core/Entry.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
|
|
||||||
|
const QCommandLineOption Clip::TotpOption = QCommandLineOption(QStringList() << "t"
|
||||||
|
<< "totp",
|
||||||
|
QObject::tr("Copy the current TOTP to the clipboard."));
|
||||||
|
|
||||||
Clip::Clip()
|
Clip::Clip()
|
||||||
{
|
{
|
||||||
name = QString("clip");
|
name = QString("clip");
|
||||||
description = QObject::tr("Copy an entry's password to the clipboard.");
|
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()
|
Clip::~Clip()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int Clip::execute(const QStringList& arguments)
|
int Clip::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||||
{
|
{
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
const QStringList args = parser->positionalArguments();
|
||||||
|
QString entryPath = args.at(1);
|
||||||
QCommandLineParser parser;
|
QString timeout;
|
||||||
parser.setApplicationDescription(description);
|
if (args.size() == 3) {
|
||||||
parser.addPositionalArgument("database", QObject::tr("Path of the database."));
|
timeout = args.at(2);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
bool clipTotp = parser->isSet(Clip::TotpOption);
|
||||||
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)
|
|
||||||
{
|
|
||||||
TextStream errorTextStream(Utils::STDERR);
|
TextStream errorTextStream(Utils::STDERR);
|
||||||
|
|
||||||
int timeoutSeconds = 0;
|
int timeoutSeconds = 0;
|
||||||
if (!timeout.isEmpty() && !timeout.toInt()) {
|
if (!timeout.isEmpty() && timeout.toInt() <= 0) {
|
||||||
errorTextStream << QObject::tr("Invalid timeout value %1.").arg(timeout) << endl;
|
errorTextStream << QObject::tr("Invalid timeout value %1.").arg(timeout) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} else if (!timeout.isEmpty()) {
|
} else if (!timeout.isEmpty()) {
|
||||||
timeoutSeconds = timeout.toInt();
|
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);
|
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
errorTextStream << QObject::tr("Entry %1 not found.").arg(entryPath) << endl;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,19 +18,17 @@
|
|||||||
#ifndef KEEPASSXC_CLIP_H
|
#ifndef KEEPASSXC_CLIP_H
|
||||||
#define KEEPASSXC_CLIP_H
|
#define KEEPASSXC_CLIP_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Clip : public Command
|
class Clip : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Clip();
|
Clip();
|
||||||
~Clip();
|
~Clip();
|
||||||
int execute(const QStringList& arguments) override;
|
|
||||||
int clipEntry(const QSharedPointer<Database>& database,
|
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||||
const QString& entryPath,
|
|
||||||
const QString& timeout,
|
static const QCommandLineOption TotpOption;
|
||||||
bool clipTotp,
|
|
||||||
bool silent);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_CLIP_H
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -35,6 +35,8 @@
|
|||||||
#include "Merge.h"
|
#include "Merge.h"
|
||||||
#include "Remove.h"
|
#include "Remove.h"
|
||||||
#include "Show.h"
|
#include "Show.h"
|
||||||
|
#include "TextStream.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
|
||||||
const QCommandLineOption Command::QuietOption =
|
const QCommandLineOption Command::QuietOption =
|
||||||
QCommandLineOption(QStringList() << "q"
|
QCommandLineOption(QStringList() << "q"
|
||||||
@ -51,13 +53,17 @@ const QCommandLineOption Command::NoPasswordOption =
|
|||||||
|
|
||||||
QMap<QString, Command*> commands;
|
QMap<QString, Command*> commands;
|
||||||
|
|
||||||
|
Command::Command()
|
||||||
|
{
|
||||||
|
options.append(Command::QuietOption);
|
||||||
|
}
|
||||||
|
|
||||||
Command::~Command()
|
Command::~Command()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Command::getDescriptionLine()
|
QString Command::getDescriptionLine()
|
||||||
{
|
{
|
||||||
|
|
||||||
QString response = name;
|
QString response = name;
|
||||||
QString space(" ");
|
QString space(" ");
|
||||||
QString spaces = space.repeated(15 - name.length());
|
QString spaces = space.repeated(15 - name.length());
|
||||||
@ -67,6 +73,36 @@ QString Command::getDescriptionLine()
|
|||||||
return response;
|
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()
|
void populateCommands()
|
||||||
{
|
{
|
||||||
if (commands.isEmpty()) {
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#define KEEPASSXC_COMMAND_H
|
#define KEEPASSXC_COMMAND_H
|
||||||
|
|
||||||
#include <QCommandLineOption>
|
#include <QCommandLineOption>
|
||||||
|
#include <QCommandLineParser>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
@ -26,14 +27,28 @@
|
|||||||
|
|
||||||
#include "core/Database.h"
|
#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
|
class Command
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
Command();
|
||||||
virtual ~Command();
|
virtual ~Command();
|
||||||
virtual int execute(const QStringList& arguments) = 0;
|
virtual int execute(const QStringList& arguments) = 0;
|
||||||
QString name;
|
QString name;
|
||||||
QString description;
|
QString description;
|
||||||
|
QList<CommandLineArgument> positionalArguments;
|
||||||
|
QList<CommandLineArgument> optionalArguments;
|
||||||
|
QList<QCommandLineOption> options;
|
||||||
QString getDescriptionLine();
|
QString getDescriptionLine();
|
||||||
|
QSharedPointer<QCommandLineParser> getCommandLineParser(const QStringList& arguments);
|
||||||
|
|
||||||
static QList<Command*> getCommands();
|
static QList<Command*> getCommands();
|
||||||
static Command* getCommand(const QString& commandName);
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,7 +18,6 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@ -35,6 +34,8 @@ Create::Create()
|
|||||||
{
|
{
|
||||||
name = QString("create");
|
name = QString("create");
|
||||||
description = QObject::tr("Create a new database.");
|
description = QObject::tr("Create a new database.");
|
||||||
|
positionalArguments.append({QString("database"), QObject::tr("Path of the database."), QString("")});
|
||||||
|
options.append(Command::KeyFileOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
Create::~Create()
|
Create::~Create()
|
||||||
@ -59,21 +60,13 @@ int Create::execute(const QStringList& arguments)
|
|||||||
QTextStream out(Utils::STDOUT, QIODevice::WriteOnly);
|
QTextStream out(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
QTextStream err(Utils::STDERR, QIODevice::WriteOnly);
|
QTextStream err(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||||
|
if (parser.isNull()) {
|
||||||
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]");
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QStringList args = parser->positionalArguments();
|
||||||
|
|
||||||
const QString& databaseFilename = args.at(0);
|
const QString& databaseFilename = args.at(0);
|
||||||
if (QFileInfo::exists(databaseFilename)) {
|
if (QFileInfo::exists(databaseFilename)) {
|
||||||
err << QObject::tr("File %1 already exists.").arg(databaseFilename) << endl;
|
err << QObject::tr("File %1 already exists.").arg(databaseFilename) << endl;
|
||||||
@ -88,8 +81,8 @@ int Create::execute(const QStringList& arguments)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<FileKey> fileKey;
|
QSharedPointer<FileKey> fileKey;
|
||||||
if (parser.isSet(Command::KeyFileOption)) {
|
if (parser->isSet(Command::KeyFileOption)) {
|
||||||
if (!loadFileKey(parser.value(Command::KeyFileOption), fileKey)) {
|
if (!loadFileKey(parser->value(Command::KeyFileOption), fileKey)) {
|
||||||
err << QObject::tr("Loading the key file failed") << endl;
|
err << QObject::tr("Loading the key file failed") << endl;
|
||||||
return EXIT_FAILURE;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,16 +20,28 @@
|
|||||||
|
|
||||||
#include "Diceware.h"
|
#include "Diceware.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "core/PassphraseGenerator.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()
|
Diceware::Diceware()
|
||||||
{
|
{
|
||||||
name = QString("diceware");
|
name = QString("diceware");
|
||||||
description = QObject::tr("Generate a new random diceware passphrase.");
|
description = QObject::tr("Generate a new random diceware passphrase.");
|
||||||
|
options.append(Diceware::WordCountOption);
|
||||||
|
options.append(Diceware::WordListOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
Diceware::~Diceware()
|
Diceware::~Diceware()
|
||||||
@ -38,45 +50,35 @@ Diceware::~Diceware()
|
|||||||
|
|
||||||
int Diceware::execute(const QStringList& arguments)
|
int Diceware::execute(const QStringList& arguments)
|
||||||
{
|
{
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
if (parser.isNull()) {
|
||||||
|
|
||||||
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]");
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
PassphraseGenerator dicewareGenerator;
|
PassphraseGenerator dicewareGenerator;
|
||||||
|
|
||||||
if (parser.value(words).isEmpty()) {
|
QString wordCount = parser->value(Diceware::WordCountOption);
|
||||||
|
if (wordCount.isEmpty()) {
|
||||||
dicewareGenerator.setWordCount(PassphraseGenerator::DefaultWordCount);
|
dicewareGenerator.setWordCount(PassphraseGenerator::DefaultWordCount);
|
||||||
|
} else if (wordCount.toInt() <= 0) {
|
||||||
|
errorTextStream << QObject::tr("Invalid word count %1").arg(wordCount) << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
int wordcount = parser.value(words).toInt();
|
dicewareGenerator.setWordCount(wordCount.toInt());
|
||||||
dicewareGenerator.setWordCount(wordcount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.value(wordlistFile).isEmpty()) {
|
QString wordListFile = parser->value(Diceware::WordListOption);
|
||||||
dicewareGenerator.setWordList(parser.value(wordlistFile));
|
if (!wordListFile.isEmpty()) {
|
||||||
|
dicewareGenerator.setWordList(wordListFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dicewareGenerator.isValid()) {
|
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;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -25,7 +25,11 @@ class Diceware : public Command
|
|||||||
public:
|
public:
|
||||||
Diceware();
|
Diceware();
|
||||||
~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
|
#endif // KEEPASSXC_DICEWARE_H
|
||||||
|
117
src/cli/Edit.cpp
117
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,8 +20,7 @@
|
|||||||
|
|
||||||
#include "Edit.h"
|
#include "Edit.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include "cli/Add.h"
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
@ -29,120 +28,80 @@
|
|||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "core/PasswordGenerator.h"
|
#include "core/PasswordGenerator.h"
|
||||||
|
|
||||||
|
const QCommandLineOption Edit::TitleOption = QCommandLineOption(QStringList() << "t"
|
||||||
|
<< "title",
|
||||||
|
QObject::tr("Title for the entry."),
|
||||||
|
QObject::tr("title"));
|
||||||
|
|
||||||
Edit::Edit()
|
Edit::Edit()
|
||||||
{
|
{
|
||||||
name = QString("edit");
|
name = QString("edit");
|
||||||
description = QObject::tr("Edit an entry.");
|
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()
|
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);
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
const QStringList args = parser->positionalArguments();
|
||||||
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 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 = Utils::unlockDatabase(databasePath,
|
QString passwordLength = parser->value(Add::PasswordLengthOption);
|
||||||
!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);
|
|
||||||
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
if (!passwordLength.isEmpty() && !passwordLength.toInt()) {
|
||||||
errorTextStream << QObject::tr("Invalid value for password length: %1").arg(passwordLength) << endl;
|
errorTextStream << QObject::tr("Invalid value for password length: %1").arg(passwordLength) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* entry = db->rootGroup()->findEntryByPath(entryPath);
|
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
errorTextStream << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl;
|
errorTextStream << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.value("username").isEmpty() && parser.value("url").isEmpty() && parser.value("title").isEmpty()
|
QString username = parser->value(Add::UsernameOption);
|
||||||
&& !parser.isSet(prompt) && !parser.isSet(generate)) {
|
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;
|
errorTextStream << QObject::tr("Not changing any field for entry %1.").arg(entryPath) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->beginUpdate();
|
entry->beginUpdate();
|
||||||
|
|
||||||
if (!parser.value("title").isEmpty()) {
|
if (!title.isEmpty()) {
|
||||||
entry->setTitle(parser.value("title"));
|
entry->setTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.value("username").isEmpty()) {
|
if (!username.isEmpty()) {
|
||||||
entry->setUsername(parser.value("username"));
|
entry->setUsername(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser.value("url").isEmpty()) {
|
if (!url.isEmpty()) {
|
||||||
entry->setUrl(parser.value("url"));
|
entry->setUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(prompt)) {
|
if (prompt) {
|
||||||
if (!parser.isSet(Command::QuietOption)) {
|
|
||||||
outputTextStream << QObject::tr("Enter new password for entry: ") << flush;
|
outputTextStream << QObject::tr("Enter new password for 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);
|
entry->setPassword(password);
|
||||||
} else if (parser.isSet(generate)) {
|
} else if (generate) {
|
||||||
PasswordGenerator passwordGenerator;
|
PasswordGenerator passwordGenerator;
|
||||||
|
|
||||||
if (passwordLength.isEmpty()) {
|
if (passwordLength.isEmpty()) {
|
||||||
@ -160,13 +119,11 @@ int Edit::execute(const QStringList& arguments)
|
|||||||
entry->endUpdate();
|
entry->endUpdate();
|
||||||
|
|
||||||
QString errorMessage;
|
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;
|
errorTextStream << QObject::tr("Writing the database failed: %1").arg(errorMessage) << endl;
|
||||||
return EXIT_FAILURE;
|
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;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,14 +18,16 @@
|
|||||||
#ifndef KEEPASSXC_EDIT_H
|
#ifndef KEEPASSXC_EDIT_H
|
||||||
#define KEEPASSXC_EDIT_H
|
#define KEEPASSXC_EDIT_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Edit : public Command
|
class Edit : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Edit();
|
Edit();
|
||||||
~Edit();
|
~Edit();
|
||||||
int execute(const QStringList& arguments) override;
|
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||||
|
|
||||||
|
static const QCommandLineOption TitleOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_EDIT_H
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,8 +18,6 @@
|
|||||||
#include "Estimate.h"
|
#include "Estimate.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -33,9 +31,17 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const QCommandLineOption Estimate::AdvancedOption =
|
||||||
|
QCommandLineOption(QStringList() << "a"
|
||||||
|
<< "advanced",
|
||||||
|
QObject::tr("Perform advanced analysis on the password."));
|
||||||
|
|
||||||
Estimate::Estimate()
|
Estimate::Estimate()
|
||||||
{
|
{
|
||||||
name = QString("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.");
|
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)
|
int Estimate::execute(const QStringList& arguments)
|
||||||
{
|
{
|
||||||
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
if (parser.isNull()) {
|
||||||
|
|
||||||
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]");
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextStream inputTextStream(Utils::STDIN, QIODevice::ReadOnly);
|
||||||
|
const QStringList args = parser->positionalArguments();
|
||||||
|
|
||||||
QString password;
|
QString password;
|
||||||
if (args.size() == 1) {
|
if (args.size() == 1) {
|
||||||
password = args.at(0);
|
password = args.at(0);
|
||||||
@ -182,6 +177,6 @@ int Estimate::execute(const QStringList& arguments)
|
|||||||
password = inputTextStream.readLine();
|
password = inputTextStream.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
estimate(password.toLatin1(), parser.isSet(advancedOption));
|
estimate(password.toLatin1(), parser->isSet(Estimate::AdvancedOption));
|
||||||
return EXIT_SUCCESS;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -26,6 +26,8 @@ public:
|
|||||||
Estimate();
|
Estimate();
|
||||||
~Estimate();
|
~Estimate();
|
||||||
int execute(const QStringList& arguments) override;
|
int execute(const QStringList& arguments) override;
|
||||||
|
|
||||||
|
static const QCommandLineOption AdvancedOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_ESTIMATE_H
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,9 +20,6 @@
|
|||||||
|
|
||||||
#include "Extract.h"
|
#include "Extract.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.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 outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, 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;
|
QByteArray xmlData;
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
if (!db->extract(xmlData, &errorMessage)) {
|
if (!database->extract(xmlData, &errorMessage)) {
|
||||||
errorTextStream << QObject::tr("Unable to extract database %1").arg(errorMessage) << endl;
|
errorTextStream << QObject::tr("Unable to extract database %1").arg(errorMessage) << endl;
|
||||||
return EXIT_FAILURE;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,14 +18,15 @@
|
|||||||
#ifndef KEEPASSXC_EXTRACT_H
|
#ifndef KEEPASSXC_EXTRACT_H
|
||||||
#define KEEPASSXC_EXTRACT_H
|
#define KEEPASSXC_EXTRACT_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Extract : public Command
|
class Extract : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Extract();
|
Extract();
|
||||||
~Extract();
|
~Extract();
|
||||||
int execute(const QStringList& arguments) override;
|
|
||||||
|
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_EXTRACT_H
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -19,17 +19,60 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "Generate.h"
|
#include "Generate.h"
|
||||||
#include "cli/Utils.h"
|
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
|
#include "cli/Utils.h"
|
||||||
#include "core/PasswordGenerator.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()
|
Generate::Generate()
|
||||||
{
|
{
|
||||||
name = QString("generate");
|
name = QString("generate");
|
||||||
description = QObject::tr("Generate a new random password.");
|
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()
|
Generate::~Generate()
|
||||||
@ -38,97 +81,59 @@ Generate::~Generate()
|
|||||||
|
|
||||||
int Generate::execute(const QStringList& arguments)
|
int Generate::execute(const QStringList& arguments)
|
||||||
{
|
{
|
||||||
|
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||||
|
if (parser.isNull()) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
const QStringList args = parser->positionalArguments();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PasswordGenerator passwordGenerator;
|
PasswordGenerator passwordGenerator;
|
||||||
|
QString passwordLength = parser->value(Generate::PasswordLengthOption);
|
||||||
if (parser.value(len).isEmpty()) {
|
if (passwordLength.isEmpty()) {
|
||||||
passwordGenerator.setLength(PasswordGenerator::DefaultLength);
|
passwordGenerator.setLength(PasswordGenerator::DefaultLength);
|
||||||
|
} else if (passwordLength.toInt() <= 0) {
|
||||||
|
errorTextStream << QObject::tr("Invalid password length %1").arg(passwordLength) << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
passwordGenerator.setLength(parser.value(len).toInt());
|
passwordGenerator.setLength(passwordLength.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
PasswordGenerator::CharClasses classes = 0x0;
|
PasswordGenerator::CharClasses classes = 0x0;
|
||||||
|
|
||||||
if (parser.isSet(lower)) {
|
if (parser->isSet(Generate::LowerCaseOption)) {
|
||||||
classes |= PasswordGenerator::LowerLetters;
|
classes |= PasswordGenerator::LowerLetters;
|
||||||
}
|
}
|
||||||
if (parser.isSet(upper)) {
|
if (parser->isSet(Generate::UpperCaseOption)) {
|
||||||
classes |= PasswordGenerator::UpperLetters;
|
classes |= PasswordGenerator::UpperLetters;
|
||||||
}
|
}
|
||||||
if (parser.isSet(numeric)) {
|
if (parser->isSet(Generate::NumbersOption)) {
|
||||||
classes |= PasswordGenerator::Numbers;
|
classes |= PasswordGenerator::Numbers;
|
||||||
}
|
}
|
||||||
if (parser.isSet(special)) {
|
if (parser->isSet(Generate::SpecialCharsOption)) {
|
||||||
classes |= PasswordGenerator::SpecialCharacters;
|
classes |= PasswordGenerator::SpecialCharacters;
|
||||||
}
|
}
|
||||||
if (parser.isSet(extended)) {
|
if (parser->isSet(Generate::ExtendedAsciiOption)) {
|
||||||
classes |= PasswordGenerator::EASCII;
|
classes |= PasswordGenerator::EASCII;
|
||||||
}
|
}
|
||||||
|
|
||||||
PasswordGenerator::GeneratorFlags flags = 0x0;
|
PasswordGenerator::GeneratorFlags flags = 0x0;
|
||||||
|
|
||||||
if (parser.isSet(exclude_similar)) {
|
if (parser->isSet(Generate::ExcludeSimilarCharsOption)) {
|
||||||
flags |= PasswordGenerator::ExcludeLookAlike;
|
flags |= PasswordGenerator::ExcludeLookAlike;
|
||||||
}
|
}
|
||||||
if (parser.isSet(every_group)) {
|
if (parser->isSet(Generate::IncludeEveryGroupOption)) {
|
||||||
flags |= PasswordGenerator::CharFromEveryGroup;
|
flags |= PasswordGenerator::CharFromEveryGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordGenerator.setCharClasses(classes);
|
passwordGenerator.setCharClasses(classes);
|
||||||
passwordGenerator.setFlags(flags);
|
passwordGenerator.setFlags(flags);
|
||||||
passwordGenerator.setExcludedChars(parser.value(exclude));
|
passwordGenerator.setExcludedChars(parser->value(Generate::ExcludeCharsOption));
|
||||||
|
|
||||||
if (!passwordGenerator.isValid()) {
|
if (!passwordGenerator.isValid()) {
|
||||||
errorTextStream << parser.helpText().replace("[options]", "generate [options]");
|
errorTextStream << QObject::tr("invalid password generator after applying all options") << endl;
|
||||||
return EXIT_FAILURE;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -26,6 +26,16 @@ public:
|
|||||||
Generate();
|
Generate();
|
||||||
~Generate();
|
~Generate();
|
||||||
int execute(const QStringList& arguments) override;
|
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
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -21,75 +21,44 @@
|
|||||||
#include "List.h"
|
#include "List.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#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/Group.h"
|
||||||
|
|
||||||
|
const QCommandLineOption List::RecursiveOption =
|
||||||
|
QCommandLineOption(QStringList() << "R"
|
||||||
|
<< "recursive",
|
||||||
|
QObject::tr("Recursively list the elements of the group."));
|
||||||
|
|
||||||
List::List()
|
List::List()
|
||||||
{
|
{
|
||||||
name = QString("ls");
|
name = QString("ls");
|
||||||
description = QObject::tr("List database entries.");
|
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()
|
List::~List()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int List::execute(const QStringList& arguments)
|
int List::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("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)
|
|
||||||
{
|
{
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, 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;
|
outputTextStream << database->rootGroup()->print(recursive) << flush;
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString groupPath = args.at(1);
|
||||||
Group* group = database->rootGroup()->findGroupByPath(groupPath);
|
Group* group = database->rootGroup()->findGroupByPath(groupPath);
|
||||||
if (!group) {
|
if (!group) {
|
||||||
errorTextStream << QObject::tr("Cannot find group %1.").arg(groupPath) << endl;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,15 +18,17 @@
|
|||||||
#ifndef KEEPASSXC_LIST_H
|
#ifndef KEEPASSXC_LIST_H
|
||||||
#define KEEPASSXC_LIST_H
|
#define KEEPASSXC_LIST_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class List : public Command
|
class List : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
List();
|
List();
|
||||||
~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
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
#include "Locate.h"
|
#include "Locate.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
@ -34,46 +33,18 @@ Locate::Locate()
|
|||||||
{
|
{
|
||||||
name = QString("locate");
|
name = QString("locate");
|
||||||
description = QObject::tr("Find entries quickly.");
|
description = QObject::tr("Find entries quickly.");
|
||||||
|
positionalArguments.append({QString("term"), QObject::tr("Search term."), QString("")});
|
||||||
}
|
}
|
||||||
|
|
||||||
Locate::~Locate()
|
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;
|
const QStringList args = parser->positionalArguments();
|
||||||
parser.setApplicationDescription(description);
|
QString searchTerm = args.at(1);
|
||||||
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)
|
|
||||||
{
|
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, 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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,15 +18,15 @@
|
|||||||
#ifndef KEEPASSXC_LOCATE_H
|
#ifndef KEEPASSXC_LOCATE_H
|
||||||
#define KEEPASSXC_LOCATE_H
|
#define KEEPASSXC_LOCATE_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Locate : public Command
|
class Locate : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Locate();
|
Locate();
|
||||||
~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
|
#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
|
* 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
|
* 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/>.
|
* 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/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Merger.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()
|
Merge::Merge()
|
||||||
{
|
{
|
||||||
name = QString("merge");
|
name = QString("merge");
|
||||||
description = QObject::tr("Merge two databases.");
|
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()
|
Merge::~Merge()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int Merge::execute(const QStringList& arguments)
|
int Merge::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||||
{
|
{
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
const QStringList args = parser->positionalArguments();
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
QSharedPointer<Database> db2;
|
QSharedPointer<Database> db2;
|
||||||
if (!parser.isSet("same-credentials")) {
|
if (!parser->isSet(Merge::SameCredentialsOption)) {
|
||||||
db2 = Utils::unlockDatabase(args.at(1),
|
db2 = Utils::unlockDatabase(args.at(1),
|
||||||
!parser.isSet(noPasswordFromOption),
|
!parser->isSet(Merge::NoPasswordFromOption),
|
||||||
parser.value(keyFileFromOption),
|
parser->value(Merge::KeyFileFromOption),
|
||||||
parser.isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
parser->isSet(Command::QuietOption) ? Utils::DEVNULL : Utils::STDOUT,
|
||||||
Utils::STDERR);
|
Utils::STDERR);
|
||||||
if (!db2) {
|
if (!db2) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -95,25 +73,25 @@ int Merge::execute(const QStringList& arguments)
|
|||||||
} else {
|
} else {
|
||||||
db2 = QSharedPointer<Database>::create();
|
db2 = QSharedPointer<Database>::create();
|
||||||
QString errorMessage;
|
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);
|
errorTextStream << QObject::tr("Error reading merge file:\n%1").arg(errorMessage);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Merger merger(db2.data(), db1.data());
|
Merger merger(db2.data(), database.data());
|
||||||
bool databaseChanged = merger.merge();
|
bool databaseChanged = merger.merge();
|
||||||
|
|
||||||
if (databaseChanged) {
|
if (databaseChanged) {
|
||||||
QString errorMessage;
|
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;
|
errorTextStream << QObject::tr("Unable to save database to file : %1").arg(errorMessage) << endl;
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!parser.isSet(Command::QuietOption)) {
|
if (!parser->isSet(Command::QuietOption)) {
|
||||||
outputTextStream << "Successfully merged the database files." << endl;
|
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;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,14 +18,19 @@
|
|||||||
#ifndef KEEPASSXC_MERGE_H
|
#ifndef KEEPASSXC_MERGE_H
|
||||||
#define KEEPASSXC_MERGE_H
|
#define KEEPASSXC_MERGE_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Merge : public Command
|
class Merge : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Merge();
|
Merge();
|
||||||
~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
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,10 +20,6 @@
|
|||||||
|
|
||||||
#include "Remove.h"
|
#include "Remove.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "cli/Utils.h"
|
#include "cli/Utils.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
@ -36,46 +32,19 @@ Remove::Remove()
|
|||||||
{
|
{
|
||||||
name = QString("rm");
|
name = QString("rm");
|
||||||
description = QString("Remove an entry from the database.");
|
description = QString("Remove an entry from the database.");
|
||||||
|
positionalArguments.append({QString("entry"), QObject::tr("Path of the entry to remove."), QString("")});
|
||||||
}
|
}
|
||||||
|
|
||||||
Remove::~Remove()
|
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 outputTextStream(quiet ? Utils::DEVNULL : Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
TextStream errorTextStream(Utils::STDERR, QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
@ -18,17 +18,15 @@
|
|||||||
#ifndef KEEPASSXC_REMOVE_H
|
#ifndef KEEPASSXC_REMOVE_H
|
||||||
#define KEEPASSXC_REMOVE_H
|
#define KEEPASSXC_REMOVE_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
#include "core/Database.h"
|
class Remove : public DatabaseCommand
|
||||||
|
|
||||||
class Remove : public Command
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Remove();
|
Remove();
|
||||||
~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
|
#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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,8 +20,6 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "cli/TextStream.h"
|
#include "cli/TextStream.h"
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
@ -29,32 +27,11 @@
|
|||||||
#include "core/Global.h"
|
#include "core/Global.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
|
|
||||||
Show::Show()
|
const QCommandLineOption Show::TotpOption = QCommandLineOption(QStringList() << "t"
|
||||||
{
|
|
||||||
name = QString("show");
|
|
||||||
description = QObject::tr("Show an entry's information.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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",
|
<< "totp",
|
||||||
QObject::tr("Show the entry's current TOTP."));
|
QObject::tr("Show the entry's current TOTP."));
|
||||||
parser.addOption(totp);
|
|
||||||
QCommandLineOption attributes(
|
const QCommandLineOption Show::AttributesOption = QCommandLineOption(
|
||||||
QStringList() << "a"
|
QStringList() << "a"
|
||||||
<< "attributes",
|
<< "attributes",
|
||||||
QObject::tr(
|
QObject::tr(
|
||||||
@ -62,34 +39,30 @@ int Show::execute(const QStringList& arguments)
|
|||||||
"This option can be specified more than once, with each attribute shown one-per-line in the given order. "
|
"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."),
|
"If no attributes are specified, a summary of the default attributes is given."),
|
||||||
QObject::tr("attribute"));
|
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();
|
Show::Show()
|
||||||
if (args.size() != 2) {
|
{
|
||||||
errorTextStream << parser.helpText().replace("[options]", "show [options]");
|
name = QString("show");
|
||||||
return EXIT_FAILURE;
|
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("")});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto db = Utils::unlockDatabase(args.at(0),
|
Show::~Show()
|
||||||
!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::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||||
}
|
|
||||||
|
|
||||||
int Show::showEntry(Database* database, QStringList attributes, bool showTotp, const QString& entryPath)
|
|
||||||
{
|
{
|
||||||
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
TextStream outputTextStream(Utils::STDOUT, QIODevice::WriteOnly);
|
||||||
TextStream errorTextStream(Utils::STDERR, 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);
|
Entry* entry = database->rootGroup()->findEntryByPath(entryPath);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
errorTextStream << QObject::tr("Could not find entry with path %1.").arg(entryPath) << endl;
|
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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,15 +18,18 @@
|
|||||||
#ifndef KEEPASSXC_SHOW_H
|
#ifndef KEEPASSXC_SHOW_H
|
||||||
#define KEEPASSXC_SHOW_H
|
#define KEEPASSXC_SHOW_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Show : public Command
|
class Show : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Show();
|
Show();
|
||||||
~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
|
#endif // KEEPASSXC_SHOW_H
|
||||||
|
@ -197,6 +197,7 @@ void TestCli::testAdd()
|
|||||||
m_stderrFile->reset();
|
m_stderrFile->reset();
|
||||||
m_stdoutFile->reset();
|
m_stdoutFile->reset();
|
||||||
m_stdoutFile->readLine(); // skip password prompt
|
m_stdoutFile->readLine(); // skip password prompt
|
||||||
|
QCOMPARE(m_stderrFile->readAll(), QByteArray(""));
|
||||||
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Successfully added entry newuser-entry.\n"));
|
QCOMPARE(m_stdoutFile->readAll(), QByteArray("Successfully added entry newuser-entry.\n"));
|
||||||
|
|
||||||
auto db = readTestDatabase();
|
auto db = readTestDatabase();
|
||||||
@ -296,7 +297,9 @@ void TestCli::testClip()
|
|||||||
// Password with timeout
|
// Password with timeout
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
// clang-format off
|
// 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
|
// clang-format on
|
||||||
|
|
||||||
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString("Password"), 500);
|
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString("Password"), 500);
|
||||||
@ -306,8 +309,9 @@ void TestCli::testClip()
|
|||||||
|
|
||||||
// TOTP with timeout
|
// TOTP with timeout
|
||||||
Utils::Test::setNextPassword("a");
|
Utils::Test::setNextPassword("a");
|
||||||
future = QtConcurrent::run(
|
future = QtConcurrent::run(&clipCmd,
|
||||||
&clipCmd, &Clip::execute, QStringList{"clip", m_dbFile->fileName(), "/Sample Entry", "1", "-t"});
|
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_VERIFY_WITH_TIMEOUT(isTOTP(clipboard->text()), 500);
|
||||||
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 1500);
|
QTRY_COMPARE_WITH_TIMEOUT(clipboard->text(), QString(""), 1500);
|
||||||
@ -316,6 +320,18 @@ void TestCli::testClip()
|
|||||||
|
|
||||||
qint64 posErr = m_stderrFile->pos();
|
qint64 posErr = m_stderrFile->pos();
|
||||||
Utils::Test::setNextPassword("a");
|
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"});
|
clipCmd.execute({"clip", m_dbFile2->fileName(), "--totp", "/Sample Entry"});
|
||||||
m_stderrFile->seek(posErr);
|
m_stderrFile->seek(posErr);
|
||||||
QCOMPARE(m_stderrFile->readAll(), QByteArray("Entry with path /Sample Entry has no TOTP set up.\n"));
|
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();
|
passphrase = m_stdoutFile->readLine();
|
||||||
QCOMPARE(passphrase.split(" ").size(), 10);
|
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;
|
TemporaryFile wordFile;
|
||||||
wordFile.open();
|
wordFile.open();
|
||||||
for (int i = 0; i < 4500; ++i) {
|
for (int i = 0; i < 4500; ++i) {
|
||||||
@ -431,6 +459,18 @@ void TestCli::testDiceware()
|
|||||||
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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void TestCli::testEdit()
|
||||||
@ -679,6 +719,23 @@ void TestCli::testGenerate()
|
|||||||
QVERIFY2(regex.match(password).hasMatch(),
|
QVERIFY2(regex.match(password).hasMatch(),
|
||||||
qPrintable("Password " + password + " does not match pattern " + pattern));
|
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()
|
void TestCli::testKeyFileOption()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user