mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
[CLI] Add a db-edit command (#8400)
This commit is contained in:
parent
b1e7c34b82
commit
db98f114f9
6
.github/CONTRIBUTING.md
vendored
6
.github/CONTRIBUTING.md
vendored
@ -85,6 +85,12 @@ All pull requests must comply with the above requirements and with the [stylegui
|
|||||||
Translations are managed on [Transifex](https://www.transifex.com/keepassxc/keepassxc/) which offers a web interface.
|
Translations are managed on [Transifex](https://www.transifex.com/keepassxc/keepassxc/) which offers a web interface.
|
||||||
Please join an existing language team or request a new one if there is none.
|
Please join an existing language team or request a new one if there is none.
|
||||||
|
|
||||||
|
If you open a Pull Request with new strings that require translations, you will need to run the following:
|
||||||
|
```
|
||||||
|
./release-tool i18n lupdate
|
||||||
|
```
|
||||||
|
This will make the new strings available for translation in Transifex.
|
||||||
|
|
||||||
## Styleguides
|
## Styleguides
|
||||||
|
|
||||||
### Git branch strategy
|
### Git branch strategy
|
||||||
|
@ -66,6 +66,11 @@ It provides the ability to query and modify the entries of a KeePass database, d
|
|||||||
The key file will be created if the file that is referred to does not exist.
|
The key file will be created if the file that is referred to does not exist.
|
||||||
If both the key file and password are empty, no database will be created.
|
If both the key file and password are empty, no database will be created.
|
||||||
|
|
||||||
|
*db-edit* [_options_] <__database__>::
|
||||||
|
Edits a database.
|
||||||
|
When setting a key file, the key file will be created if the file that is referred to
|
||||||
|
does not exist.
|
||||||
|
|
||||||
*db-info* [_options_] <__database__>::
|
*db-info* [_options_] <__database__>::
|
||||||
Show a database's information.
|
Show a database's information.
|
||||||
|
|
||||||
@ -154,7 +159,7 @@ It provides the ability to query and modify the entries of a KeePass database, d
|
|||||||
*--no-password*::
|
*--no-password*::
|
||||||
Deactivates the password key for the database.
|
Deactivates the password key for the database.
|
||||||
|
|
||||||
*-y*, *--yubikey* <__slot__>::
|
*-y*, *--yubikey* <__slot[:serial]__>::
|
||||||
Specifies a yubikey slot for unlocking the database.
|
Specifies a yubikey slot for unlocking the database.
|
||||||
In a merge operation this option is used to specify the YubiKey slot for the first database.
|
In a merge operation this option is used to specify the YubiKey slot for the first database.
|
||||||
|
|
||||||
@ -177,7 +182,7 @@ It provides the ability to query and modify the entries of a KeePass database, d
|
|||||||
*--no-password-from*::
|
*--no-password-from*::
|
||||||
Deactivates password key for the database to merge from.
|
Deactivates password key for the database to merge from.
|
||||||
|
|
||||||
*--yubikey-from* <__slot__>::
|
*--yubikey-from* <__slot[:serial]__>::
|
||||||
YubiKey slot for the second database.
|
YubiKey slot for the second database.
|
||||||
|
|
||||||
*-s*, *--same-credentials*::
|
*-s*, *--same-credentials*::
|
||||||
@ -235,16 +240,24 @@ The same password generation options as documented for the generate command can
|
|||||||
If a unique matching entry is found it will be copied to the clipboard.
|
If a unique matching entry is found it will be copied to the clipboard.
|
||||||
If multiple entries are found they will be listed to refine the search. (no clip performed)
|
If multiple entries are found they will be listed to refine the search. (no clip performed)
|
||||||
|
|
||||||
=== Create and Import options
|
=== Db-create, Db-edit and Import options
|
||||||
*-k*, *--set-key-file* <__path__>::
|
*--set-key-file* <__path__>::
|
||||||
Set the key file for the database.
|
Set the key file for the database.
|
||||||
|
|
||||||
*-p*, *--set-password*::
|
*-p*, *--set-password*::
|
||||||
Set a password for the database.
|
Set a password for the database.
|
||||||
|
|
||||||
|
=== Db-create, Import options
|
||||||
*-t*, *--decryption-time* <__time__>::
|
*-t*, *--decryption-time* <__time__>::
|
||||||
Target decryption time in MS for the database.
|
Target decryption time in MS for the database.
|
||||||
|
|
||||||
|
=== Db-edit options
|
||||||
|
*--unset-password* <__path__>::
|
||||||
|
Removes the password for the database.
|
||||||
|
|
||||||
|
*--unset-key-file* <__path__>::
|
||||||
|
Removes the key file for the database.
|
||||||
|
|
||||||
=== Show options
|
=== Show options
|
||||||
*-a*, *--attributes* <__attribute__>...::
|
*-a*, *--attributes* <__attribute__>...::
|
||||||
Shows the named attributes.
|
Shows the named attributes.
|
||||||
|
@ -7871,6 +7871,59 @@ Kernel: %3 %4</source>
|
|||||||
<source>Show all the attributes of the entry.</source>
|
<source>Show all the attributes of the entry.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Edit a database.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Could not change the database key.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Database was not modified.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Successfully edited the database.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Loading the new key file failed: %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unset the password for the database.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unset the key file for the database.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Cannot use %1 and %2 at the same time.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Cannot remove all the keys from a database.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Cannot remove password: The database does not have a password.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Cannot remove file key: The database does not have a file key.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Found unexpected Key type %1</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Set the key file for the database.
|
||||||
|
This options is deprecated, use --set-key-file instead.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>QtIOCompressor</name>
|
<name>QtIOCompressor</name>
|
||||||
|
@ -22,9 +22,11 @@ set(cli_SOURCES
|
|||||||
AttachmentRemove.cpp
|
AttachmentRemove.cpp
|
||||||
Clip.cpp
|
Clip.cpp
|
||||||
Close.cpp
|
Close.cpp
|
||||||
Create.cpp
|
|
||||||
Command.cpp
|
Command.cpp
|
||||||
DatabaseCommand.cpp
|
DatabaseCommand.cpp
|
||||||
|
DatabaseCreate.cpp
|
||||||
|
DatabaseEdit.cpp
|
||||||
|
DatabaseInfo.cpp
|
||||||
Diceware.cpp
|
Diceware.cpp
|
||||||
Edit.cpp
|
Edit.cpp
|
||||||
Estimate.cpp
|
Estimate.cpp
|
||||||
@ -33,7 +35,6 @@ set(cli_SOURCES
|
|||||||
Generate.cpp
|
Generate.cpp
|
||||||
Help.cpp
|
Help.cpp
|
||||||
Import.cpp
|
Import.cpp
|
||||||
Info.cpp
|
|
||||||
List.cpp
|
List.cpp
|
||||||
Merge.cpp
|
Merge.cpp
|
||||||
Move.cpp
|
Move.cpp
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
#include "AttachmentRemove.h"
|
#include "AttachmentRemove.h"
|
||||||
#include "Clip.h"
|
#include "Clip.h"
|
||||||
#include "Close.h"
|
#include "Close.h"
|
||||||
#include "Create.h"
|
#include "DatabaseCreate.h"
|
||||||
|
#include "DatabaseEdit.h"
|
||||||
|
#include "DatabaseInfo.h"
|
||||||
#include "Diceware.h"
|
#include "Diceware.h"
|
||||||
#include "Edit.h"
|
#include "Edit.h"
|
||||||
#include "Estimate.h"
|
#include "Estimate.h"
|
||||||
@ -32,7 +34,6 @@
|
|||||||
#include "Generate.h"
|
#include "Generate.h"
|
||||||
#include "Help.h"
|
#include "Help.h"
|
||||||
#include "Import.h"
|
#include "Import.h"
|
||||||
#include "Info.h"
|
|
||||||
#include "List.h"
|
#include "List.h"
|
||||||
#include "Merge.h"
|
#include "Merge.h"
|
||||||
#include "Move.h"
|
#include "Move.h"
|
||||||
@ -172,8 +173,9 @@ namespace Commands
|
|||||||
s_commands.insert(QStringLiteral("attachment-rm"), QSharedPointer<Command>(new AttachmentRemove()));
|
s_commands.insert(QStringLiteral("attachment-rm"), QSharedPointer<Command>(new AttachmentRemove()));
|
||||||
s_commands.insert(QStringLiteral("clip"), QSharedPointer<Command>(new Clip()));
|
s_commands.insert(QStringLiteral("clip"), QSharedPointer<Command>(new Clip()));
|
||||||
s_commands.insert(QStringLiteral("close"), QSharedPointer<Command>(new Close()));
|
s_commands.insert(QStringLiteral("close"), QSharedPointer<Command>(new Close()));
|
||||||
s_commands.insert(QStringLiteral("db-create"), QSharedPointer<Command>(new Create()));
|
s_commands.insert(QStringLiteral("db-create"), QSharedPointer<Command>(new DatabaseCreate()));
|
||||||
s_commands.insert(QStringLiteral("db-info"), QSharedPointer<Command>(new Info()));
|
s_commands.insert(QStringLiteral("db-edit"), QSharedPointer<Command>(new DatabaseEdit()));
|
||||||
|
s_commands.insert(QStringLiteral("db-info"), QSharedPointer<Command>(new DatabaseInfo()));
|
||||||
s_commands.insert(QStringLiteral("diceware"), QSharedPointer<Command>(new Diceware()));
|
s_commands.insert(QStringLiteral("diceware"), QSharedPointer<Command>(new Diceware()));
|
||||||
s_commands.insert(QStringLiteral("edit"), QSharedPointer<Command>(new Edit()));
|
s_commands.insert(QStringLiteral("edit"), QSharedPointer<Command>(new Edit()));
|
||||||
s_commands.insert(QStringLiteral("estimate"), QSharedPointer<Command>(new Estimate()));
|
s_commands.insert(QStringLiteral("estimate"), QSharedPointer<Command>(new Estimate()));
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* 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 "Create.h"
|
#include "DatabaseCreate.h"
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "keys/FileKey.h"
|
#include "keys/FileKey.h"
|
||||||
@ -23,34 +23,39 @@
|
|||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
const QCommandLineOption Create::DecryptionTimeOption =
|
const QCommandLineOption DatabaseCreate::DecryptionTimeOption =
|
||||||
QCommandLineOption(QStringList() << "t"
|
QCommandLineOption(QStringList() << "t"
|
||||||
<< "decryption-time",
|
<< "decryption-time",
|
||||||
QObject::tr("Target decryption time in MS for the database."),
|
QObject::tr("Target decryption time in MS for the database."),
|
||||||
QObject::tr("time"));
|
QObject::tr("time"));
|
||||||
|
|
||||||
const QCommandLineOption Create::SetKeyFileOption =
|
const QCommandLineOption DatabaseCreate::SetKeyFileShortOption = QCommandLineOption(
|
||||||
QCommandLineOption(QStringList() << "k"
|
QStringList() << "k",
|
||||||
<< "set-key-file",
|
QObject::tr("Set the key file for the database.\nThis options is deprecated, use --set-key-file instead."),
|
||||||
|
QObject::tr("path"));
|
||||||
|
|
||||||
|
const QCommandLineOption DatabaseCreate::SetKeyFileOption =
|
||||||
|
QCommandLineOption(QStringList() << "set-key-file",
|
||||||
QObject::tr("Set the key file for the database."),
|
QObject::tr("Set the key file for the database."),
|
||||||
QObject::tr("path"));
|
QObject::tr("path"));
|
||||||
|
|
||||||
const QCommandLineOption Create::SetPasswordOption =
|
const QCommandLineOption DatabaseCreate::SetPasswordOption =
|
||||||
QCommandLineOption(QStringList() << "p"
|
QCommandLineOption(QStringList() << "p"
|
||||||
<< "set-password",
|
<< "set-password",
|
||||||
QObject::tr("Set a password for the database."));
|
QObject::tr("Set a password for the database."));
|
||||||
|
|
||||||
Create::Create()
|
DatabaseCreate::DatabaseCreate()
|
||||||
{
|
{
|
||||||
name = QString("db-create");
|
name = QString("db-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("")});
|
positionalArguments.append({QString("database"), QObject::tr("Path of the database."), QString("")});
|
||||||
options.append(Create::SetKeyFileOption);
|
options.append(DatabaseCreate::SetKeyFileOption);
|
||||||
options.append(Create::SetPasswordOption);
|
options.append(DatabaseCreate::SetKeyFileShortOption);
|
||||||
options.append(Create::DecryptionTimeOption);
|
options.append(DatabaseCreate::SetPasswordOption);
|
||||||
|
options.append(DatabaseCreate::DecryptionTimeOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Database> Create::initializeDatabaseFromOptions(const QSharedPointer<QCommandLineParser>& parser)
|
QSharedPointer<Database> DatabaseCreate::initializeDatabaseFromOptions(const QSharedPointer<QCommandLineParser>& parser)
|
||||||
{
|
{
|
||||||
if (parser.isNull()) {
|
if (parser.isNull()) {
|
||||||
return {};
|
return {};
|
||||||
@ -60,7 +65,7 @@ QSharedPointer<Database> Create::initializeDatabaseFromOptions(const QSharedPoin
|
|||||||
auto& err = Utils::STDERR;
|
auto& err = Utils::STDERR;
|
||||||
|
|
||||||
// Validate the decryption time before asking for a password.
|
// Validate the decryption time before asking for a password.
|
||||||
QString decryptionTimeValue = parser->value(Create::DecryptionTimeOption);
|
QString decryptionTimeValue = parser->value(DatabaseCreate::DecryptionTimeOption);
|
||||||
int decryptionTime = 0;
|
int decryptionTime = 0;
|
||||||
if (decryptionTimeValue.length() != 0) {
|
if (decryptionTimeValue.length() != 0) {
|
||||||
decryptionTime = decryptionTimeValue.toInt();
|
decryptionTime = decryptionTimeValue.toInt();
|
||||||
@ -78,7 +83,7 @@ QSharedPointer<Database> Create::initializeDatabaseFromOptions(const QSharedPoin
|
|||||||
|
|
||||||
auto key = QSharedPointer<CompositeKey>::create();
|
auto key = QSharedPointer<CompositeKey>::create();
|
||||||
|
|
||||||
if (parser->isSet(Create::SetPasswordOption)) {
|
if (parser->isSet(DatabaseCreate::SetPasswordOption)) {
|
||||||
auto passwordKey = Utils::getConfirmedPassword();
|
auto passwordKey = Utils::getConfirmedPassword();
|
||||||
if (passwordKey.isNull()) {
|
if (passwordKey.isNull()) {
|
||||||
err << QObject::tr("Failed to set database password.") << endl;
|
err << QObject::tr("Failed to set database password.") << endl;
|
||||||
@ -87,10 +92,18 @@ QSharedPointer<Database> Create::initializeDatabaseFromOptions(const QSharedPoin
|
|||||||
key->addKey(passwordKey);
|
key->addKey(passwordKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser->isSet(Create::SetKeyFileOption)) {
|
if (parser->isSet(DatabaseCreate::SetKeyFileOption) || parser->isSet(DatabaseCreate::SetKeyFileShortOption)) {
|
||||||
QSharedPointer<FileKey> fileKey;
|
QSharedPointer<FileKey> fileKey;
|
||||||
|
|
||||||
if (!Utils::loadFileKey(parser->value(Create::SetKeyFileOption), fileKey)) {
|
QString keyFilePath;
|
||||||
|
if (parser->isSet(DatabaseCreate::SetKeyFileShortOption)) {
|
||||||
|
qWarning("The -k option will be deprecated. Please use the --set-key-file option instead.");
|
||||||
|
keyFilePath = parser->value(DatabaseCreate::SetKeyFileShortOption);
|
||||||
|
} else {
|
||||||
|
keyFilePath = parser->value(DatabaseCreate::SetKeyFileOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils::loadFileKey(keyFilePath, fileKey)) {
|
||||||
err << QObject::tr("Loading the key file failed") << endl;
|
err << QObject::tr("Loading the key file failed") << endl;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -141,7 +154,7 @@ QSharedPointer<Database> Create::initializeDatabaseFromOptions(const QSharedPoin
|
|||||||
*
|
*
|
||||||
* @return EXIT_SUCCESS on success, or EXIT_FAILURE on failure
|
* @return EXIT_SUCCESS on success, or EXIT_FAILURE on failure
|
||||||
*/
|
*/
|
||||||
int Create::execute(const QStringList& arguments)
|
int DatabaseCreate::execute(const QStringList& arguments)
|
||||||
{
|
{
|
||||||
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
QSharedPointer<QCommandLineParser> parser = getCommandLineParser(arguments);
|
||||||
if (parser.isNull()) {
|
if (parser.isNull()) {
|
||||||
@ -159,7 +172,7 @@ int Create::execute(const QStringList& arguments)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Database> db = Create::initializeDatabaseFromOptions(parser);
|
QSharedPointer<Database> db = DatabaseCreate::initializeDatabaseFromOptions(parser);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
@ -15,22 +15,23 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef KEEPASSXC_CREATE_H
|
#ifndef KEEPASSXC_DATABASECREATE_H
|
||||||
#define KEEPASSXC_CREATE_H
|
#define KEEPASSXC_DATABASECREATE_H
|
||||||
|
|
||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
|
|
||||||
class Create : public Command
|
class DatabaseCreate : public Command
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Create();
|
DatabaseCreate();
|
||||||
int execute(const QStringList& arguments) override;
|
int execute(const QStringList& arguments) override;
|
||||||
|
|
||||||
static QSharedPointer<Database> initializeDatabaseFromOptions(const QSharedPointer<QCommandLineParser>& parser);
|
static QSharedPointer<Database> initializeDatabaseFromOptions(const QSharedPointer<QCommandLineParser>& parser);
|
||||||
|
|
||||||
static const QCommandLineOption SetKeyFileOption;
|
static const QCommandLineOption SetKeyFileOption;
|
||||||
|
static const QCommandLineOption SetKeyFileShortOption;
|
||||||
static const QCommandLineOption SetPasswordOption;
|
static const QCommandLineOption SetPasswordOption;
|
||||||
static const QCommandLineOption DecryptionTimeOption;
|
static const QCommandLineOption DecryptionTimeOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_CREATE_H
|
#endif // KEEPASSXC_DATABASECREATE_H
|
174
src/cli/DatabaseEdit.cpp
Normal file
174
src/cli/DatabaseEdit.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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 "DatabaseEdit.h"
|
||||||
|
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "cli/DatabaseCreate.h"
|
||||||
|
#include "keys/ChallengeResponseKey.h"
|
||||||
|
#include "keys/FileKey.h"
|
||||||
|
#include "keys/PasswordKey.h"
|
||||||
|
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
const QCommandLineOption DatabaseEdit::UnsetPasswordOption =
|
||||||
|
QCommandLineOption(QStringList() << "unset-password", QObject::tr("Unset the password for the database."));
|
||||||
|
const QCommandLineOption DatabaseEdit::UnsetKeyFileOption =
|
||||||
|
QCommandLineOption(QStringList() << "unset-key-file", QObject::tr("Unset the key file for the database."));
|
||||||
|
|
||||||
|
DatabaseEdit::DatabaseEdit()
|
||||||
|
{
|
||||||
|
name = QString("db-edit");
|
||||||
|
description = QObject::tr("Edit a database.");
|
||||||
|
options.append(DatabaseCreate::SetKeyFileOption);
|
||||||
|
options.append(DatabaseCreate::SetPasswordOption);
|
||||||
|
options.append(DatabaseEdit::UnsetKeyFileOption);
|
||||||
|
options.append(DatabaseEdit::UnsetPasswordOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DatabaseEdit::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser> parser)
|
||||||
|
{
|
||||||
|
auto& out = Utils::STDOUT;
|
||||||
|
auto& err = Utils::STDERR;
|
||||||
|
|
||||||
|
const QStringList args = parser->positionalArguments();
|
||||||
|
bool databaseWasChanged = false;
|
||||||
|
|
||||||
|
if (parser->isSet(DatabaseCreate::SetPasswordOption) && parser->isSet(DatabaseEdit::UnsetPasswordOption)) {
|
||||||
|
err << QObject::tr("Cannot use %1 and %2 at the same time.")
|
||||||
|
.arg(DatabaseCreate::SetPasswordOption.names().at(0))
|
||||||
|
.arg(DatabaseEdit::UnsetPasswordOption.names().at(0))
|
||||||
|
<< endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser->isSet(DatabaseCreate::SetKeyFileOption) && parser->isSet(DatabaseEdit::UnsetKeyFileOption)) {
|
||||||
|
err << QObject::tr("Cannot use %1 and %2 at the same time.")
|
||||||
|
.arg(DatabaseCreate::SetKeyFileOption.names().at(0))
|
||||||
|
.arg(DatabaseEdit::UnsetKeyFileOption.names().at(0))
|
||||||
|
<< endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasKeyChange =
|
||||||
|
(parser->isSet(DatabaseCreate::SetPasswordOption) || parser->isSet(DatabaseCreate::SetKeyFileOption)
|
||||||
|
|| parser->isSet(DatabaseEdit::UnsetPasswordOption) || parser->isSet(DatabaseEdit::UnsetKeyFileOption));
|
||||||
|
|
||||||
|
if (hasKeyChange) {
|
||||||
|
auto newDatabaseKey = getNewDatabaseKey(database,
|
||||||
|
parser->isSet(DatabaseCreate::SetPasswordOption),
|
||||||
|
parser->isSet(DatabaseEdit::UnsetPasswordOption),
|
||||||
|
parser->value(DatabaseCreate::SetKeyFileOption),
|
||||||
|
parser->isSet(DatabaseEdit::UnsetKeyFileOption));
|
||||||
|
if (newDatabaseKey.isNull()) {
|
||||||
|
err << QObject::tr("Could not change the database key.") << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
database->setKey(newDatabaseKey);
|
||||||
|
databaseWasChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!databaseWasChanged) {
|
||||||
|
out << QObject::tr("Database was not modified.") << endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
if (!database->save(Database::Atomic, {}, &errorMessage)) {
|
||||||
|
err << QObject::tr("Writing the database failed: %1").arg(errorMessage) << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
out << QObject::tr("Successfully edited the database.") << endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSharedPointer<CompositeKey> DatabaseEdit::getNewDatabaseKey(QSharedPointer<Database> database,
|
||||||
|
bool updatePassword,
|
||||||
|
bool removePassword,
|
||||||
|
QString newFileKeyPath,
|
||||||
|
bool removeKeyFile)
|
||||||
|
{
|
||||||
|
auto& err = Utils::STDERR;
|
||||||
|
auto newDatabaseKey = QSharedPointer<CompositeKey>::create();
|
||||||
|
bool updateKeyFile = !newFileKeyPath.isEmpty();
|
||||||
|
|
||||||
|
auto currentPasswordKey = database->key()->getKey(PasswordKey::UUID);
|
||||||
|
auto currentFileKey = database->key()->getKey(FileKey::UUID);
|
||||||
|
auto currentChallengeResponseKey = database->key()->getChallengeResponseKey(ChallengeResponseKey::UUID);
|
||||||
|
|
||||||
|
if (removePassword && currentPasswordKey.isNull()) {
|
||||||
|
err << QObject::tr("Cannot remove password: The database does not have a password.") << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeKeyFile && currentFileKey.isNull()) {
|
||||||
|
err << QObject::tr("Cannot remove file key: The database does not have a file key.") << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatePassword) {
|
||||||
|
QSharedPointer<PasswordKey> newPasswordKey = Utils::getConfirmedPassword();
|
||||||
|
if (newPasswordKey.isNull()) {
|
||||||
|
err << QObject::tr("Failed to set database password.") << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
newDatabaseKey->addKey(newPasswordKey);
|
||||||
|
} else if (!removePassword && !currentPasswordKey.isNull()) {
|
||||||
|
newDatabaseKey->addKey(currentPasswordKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateKeyFile) {
|
||||||
|
QSharedPointer<FileKey> newFileKey = QSharedPointer<FileKey>::create();
|
||||||
|
QString errorMessage;
|
||||||
|
if (!Utils::loadFileKey(newFileKeyPath, newFileKey)) {
|
||||||
|
err << QObject::tr("Loading the new key file failed: %1").arg(errorMessage) << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
newDatabaseKey->addKey(newFileKey);
|
||||||
|
} else if (!removeKeyFile && !currentFileKey.isNull()) {
|
||||||
|
newDatabaseKey->addKey(currentFileKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a sanity check to make sure that this function is not used if
|
||||||
|
// new key types are introduced. Otherwise, those key types would be
|
||||||
|
// silently removed from the database.
|
||||||
|
for (const QSharedPointer<Key>& key : database->key()->keys()) {
|
||||||
|
if (key->uuid() != PasswordKey::UUID && key->uuid() != FileKey::UUID) {
|
||||||
|
err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const QSharedPointer<ChallengeResponseKey>& key : database->key()->challengeResponseKeys()) {
|
||||||
|
if (key->uuid() != ChallengeResponseKey::UUID) {
|
||||||
|
err << QObject::tr("Found unexpected Key type %1").arg(key->uuid().toString()) << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentChallengeResponseKey.isNull()) {
|
||||||
|
newDatabaseKey->addChallengeResponseKey(currentChallengeResponseKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newDatabaseKey->keys().isEmpty() && newDatabaseKey->challengeResponseKeys().isEmpty()) {
|
||||||
|
err << QObject::tr("Cannot remove all the keys from a database.") << endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return newDatabaseKey;
|
||||||
|
}
|
41
src/cli/DatabaseEdit.h
Normal file
41
src/cli/DatabaseEdit.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 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_DATABASEEDIT_H
|
||||||
|
#define KEEPASSXC_DATABASEEDIT_H
|
||||||
|
|
||||||
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
|
class DatabaseEdit : public DatabaseCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DatabaseEdit();
|
||||||
|
|
||||||
|
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser) override;
|
||||||
|
|
||||||
|
static const QCommandLineOption UnsetKeyFileOption;
|
||||||
|
static const QCommandLineOption UnsetPasswordOption;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSharedPointer<CompositeKey> getNewDatabaseKey(QSharedPointer<Database> database,
|
||||||
|
bool updatePassword,
|
||||||
|
bool removePassword,
|
||||||
|
QString newFileKeyPath,
|
||||||
|
bool removeKeyFile);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSXC_DATABASEEDIT_H
|
@ -15,7 +15,7 @@
|
|||||||
* 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 "Info.h"
|
#include "DatabaseInfo.h"
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "core/DatabaseStats.h"
|
#include "core/DatabaseStats.h"
|
||||||
@ -25,13 +25,13 @@
|
|||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
|
|
||||||
Info::Info()
|
DatabaseInfo::DatabaseInfo()
|
||||||
{
|
{
|
||||||
name = QString("db-info");
|
name = QString("db-info");
|
||||||
description = QObject::tr("Show a database's information.");
|
description = QObject::tr("Show a database's information.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int Info::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser>)
|
int DatabaseInfo::executeWithDatabase(QSharedPointer<Database> database, QSharedPointer<QCommandLineParser>)
|
||||||
{
|
{
|
||||||
auto& out = Utils::STDOUT;
|
auto& out = Utils::STDOUT;
|
||||||
|
|
@ -15,17 +15,17 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef KEEPASSXC_INFO_H
|
#ifndef KEEPASSXC_DATABASEINFO_H
|
||||||
#define KEEPASSXC_INFO_H
|
#define KEEPASSXC_DATABASEINFO_H
|
||||||
|
|
||||||
#include "DatabaseCommand.h"
|
#include "DatabaseCommand.h"
|
||||||
|
|
||||||
class Info : public DatabaseCommand
|
class DatabaseInfo : public DatabaseCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Info();
|
DatabaseInfo();
|
||||||
|
|
||||||
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser) override;
|
int executeWithDatabase(QSharedPointer<Database> db, QSharedPointer<QCommandLineParser> parser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSXC_INFO_H
|
#endif // KEEPASSXC_DATABASEINFO_H
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include "Import.h"
|
#include "Import.h"
|
||||||
|
|
||||||
#include "Create.h"
|
#include "DatabaseCreate.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
@ -40,9 +40,10 @@ Import::Import()
|
|||||||
description = QObject::tr("Import the contents of an XML database.");
|
description = QObject::tr("Import the contents of an XML database.");
|
||||||
positionalArguments.append({QString("xml"), QObject::tr("Path of the XML database export."), QString("")});
|
positionalArguments.append({QString("xml"), QObject::tr("Path of the XML database export."), QString("")});
|
||||||
positionalArguments.append({QString("database"), QObject::tr("Path of the new database."), QString("")});
|
positionalArguments.append({QString("database"), QObject::tr("Path of the new database."), QString("")});
|
||||||
options.append(Create::SetKeyFileOption);
|
options.append(DatabaseCreate::SetKeyFileOption);
|
||||||
options.append(Create::SetPasswordOption);
|
options.append(DatabaseCreate::SetKeyFileShortOption);
|
||||||
options.append(Create::DecryptionTimeOption);
|
options.append(DatabaseCreate::SetPasswordOption);
|
||||||
|
options.append(DatabaseCreate::DecryptionTimeOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Import::execute(const QStringList& arguments)
|
int Import::execute(const QStringList& arguments)
|
||||||
@ -64,7 +65,7 @@ int Import::execute(const QStringList& arguments)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Database> db = Create::initializeDatabaseFromOptions(parser);
|
QSharedPointer<Database> db = DatabaseCreate::initializeDatabaseFromOptions(parser);
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,36 @@ void CompositeKey::addKey(const QSharedPointer<Key>& key)
|
|||||||
m_keys.append(key);
|
m_keys.append(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the \link Key with the specified ID.
|
||||||
|
*
|
||||||
|
* @param keyId the ID of the key to get.
|
||||||
|
*/
|
||||||
|
QSharedPointer<Key> CompositeKey::getKey(const QUuid keyId) const
|
||||||
|
{
|
||||||
|
for (const QSharedPointer<Key>& key : m_keys) {
|
||||||
|
if (key->uuid() == keyId) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the \link ChallengeResponseKey with the specified ID.
|
||||||
|
*
|
||||||
|
* @param keyId the ID of the key to get.
|
||||||
|
*/
|
||||||
|
QSharedPointer<ChallengeResponseKey> CompositeKey::getChallengeResponseKey(const QUuid keyId) const
|
||||||
|
{
|
||||||
|
for (const QSharedPointer<ChallengeResponseKey>& key : m_challengeResponseKeys) {
|
||||||
|
if (key->uuid() == keyId) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list of Keys which are part of this CompositeKey
|
* @return list of Keys which are part of this CompositeKey
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +43,8 @@ public:
|
|||||||
bool challenge(const QByteArray& seed, QByteArray& result, QString* error = nullptr) const;
|
bool challenge(const QByteArray& seed, QByteArray& result, QString* error = nullptr) const;
|
||||||
|
|
||||||
void addKey(const QSharedPointer<Key>& key);
|
void addKey(const QSharedPointer<Key>& key);
|
||||||
|
QSharedPointer<Key> getKey(const QUuid keyType) const;
|
||||||
|
QSharedPointer<ChallengeResponseKey> getChallengeResponseKey(const QUuid keyType) const;
|
||||||
const QList<QSharedPointer<Key>>& keys() const;
|
const QList<QSharedPointer<Key>>& keys() const;
|
||||||
|
|
||||||
void addChallengeResponseKey(const QSharedPointer<ChallengeResponseKey>& key);
|
void addChallengeResponseKey(const QSharedPointer<ChallengeResponseKey>& key);
|
||||||
|
@ -34,7 +34,9 @@
|
|||||||
#include "cli/AttachmentImport.h"
|
#include "cli/AttachmentImport.h"
|
||||||
#include "cli/AttachmentRemove.h"
|
#include "cli/AttachmentRemove.h"
|
||||||
#include "cli/Clip.h"
|
#include "cli/Clip.h"
|
||||||
#include "cli/Create.h"
|
#include "cli/DatabaseCreate.h"
|
||||||
|
#include "cli/DatabaseEdit.h"
|
||||||
|
#include "cli/DatabaseInfo.h"
|
||||||
#include "cli/Diceware.h"
|
#include "cli/Diceware.h"
|
||||||
#include "cli/Edit.h"
|
#include "cli/Edit.h"
|
||||||
#include "cli/Estimate.h"
|
#include "cli/Estimate.h"
|
||||||
@ -42,7 +44,6 @@
|
|||||||
#include "cli/Generate.h"
|
#include "cli/Generate.h"
|
||||||
#include "cli/Help.h"
|
#include "cli/Help.h"
|
||||||
#include "cli/Import.h"
|
#include "cli/Import.h"
|
||||||
#include "cli/Info.h"
|
|
||||||
#include "cli/List.h"
|
#include "cli/List.h"
|
||||||
#include "cli/Merge.h"
|
#include "cli/Merge.h"
|
||||||
#include "cli/Move.h"
|
#include "cli/Move.h"
|
||||||
@ -242,7 +243,7 @@ void TestCli::testBatchCommands()
|
|||||||
QVERIFY(Commands::getCommand("show"));
|
QVERIFY(Commands::getCommand("show"));
|
||||||
QVERIFY(Commands::getCommand("search"));
|
QVERIFY(Commands::getCommand("search"));
|
||||||
QVERIFY(!Commands::getCommand("doesnotexist"));
|
QVERIFY(!Commands::getCommand("doesnotexist"));
|
||||||
QCOMPARE(Commands::getCommands().size(), 25);
|
QCOMPARE(Commands::getCommands().size(), 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCli::testInteractiveCommands()
|
void TestCli::testInteractiveCommands()
|
||||||
@ -274,7 +275,7 @@ void TestCli::testInteractiveCommands()
|
|||||||
QVERIFY(Commands::getCommand("show"));
|
QVERIFY(Commands::getCommand("show"));
|
||||||
QVERIFY(Commands::getCommand("search"));
|
QVERIFY(Commands::getCommand("search"));
|
||||||
QVERIFY(!Commands::getCommand("doesnotexist"));
|
QVERIFY(!Commands::getCommand("doesnotexist"));
|
||||||
QCOMPARE(Commands::getCommands().size(), 25);
|
QCOMPARE(Commands::getCommands().size(), 26);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCli::testAdd()
|
void TestCli::testAdd()
|
||||||
@ -732,7 +733,7 @@ void TestCli::testClip()
|
|||||||
|
|
||||||
void TestCli::testCreate()
|
void TestCli::testCreate()
|
||||||
{
|
{
|
||||||
Create createCmd;
|
DatabaseCreate createCmd;
|
||||||
QVERIFY(!createCmd.name.isEmpty());
|
QVERIFY(!createCmd.name.isEmpty());
|
||||||
QVERIFY(createCmd.getDescriptionLine().contains(createCmd.name));
|
QVERIFY(createCmd.getDescriptionLine().contains(createCmd.name));
|
||||||
|
|
||||||
@ -848,9 +849,147 @@ void TestCli::testCreate()
|
|||||||
QVERIFY(db);
|
QVERIFY(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestCli::testDatabaseEdit()
|
||||||
|
{
|
||||||
|
TemporaryFile firstKeyFile;
|
||||||
|
firstKeyFile.open();
|
||||||
|
firstKeyFile.write(QString("keyFilePassword").toLatin1());
|
||||||
|
firstKeyFile.close();
|
||||||
|
|
||||||
|
TemporaryFile secondKeyFile;
|
||||||
|
secondKeyFile.open();
|
||||||
|
secondKeyFile.write(QString("newKeyFilePassword").toLatin1());
|
||||||
|
secondKeyFile.close();
|
||||||
|
|
||||||
|
QScopedPointer<QTemporaryDir> testDir(new QTemporaryDir());
|
||||||
|
|
||||||
|
DatabaseCreate createCmd;
|
||||||
|
DatabaseEdit editCmd;
|
||||||
|
QVERIFY(!editCmd.name.isEmpty());
|
||||||
|
QVERIFY(editCmd.getDescriptionLine().contains(editCmd.name));
|
||||||
|
|
||||||
|
QString dbFilename;
|
||||||
|
dbFilename = testDir->path() + "/testDatabaseEdit.kdbx";
|
||||||
|
|
||||||
|
// Creating a database for testing
|
||||||
|
setInput({"a", "a"});
|
||||||
|
execCmd(createCmd, {"db-create", dbFilename, "-p"});
|
||||||
|
QCOMPARE(m_stdout->readLine(), QByteArray("Successfully created new database.\n"));
|
||||||
|
|
||||||
|
// Sanity check.
|
||||||
|
auto db = readDatabase(dbFilename, "a");
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
setInput("a");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-p", "--unset-password"});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray(""));
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray("Cannot use p and unset-password at the same time.\n"));
|
||||||
|
|
||||||
|
setInput("a");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "--set-key-file", "/key/file/path", "--unset-key-file"});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray(""));
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray("Cannot use set-key-file and unset-key-file at the same time.\n"));
|
||||||
|
|
||||||
|
// Sanity check.
|
||||||
|
db = readDatabase(dbFilename, "a");
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
setInput({"a", "b", "b"});
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-p"});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
db = readDatabase(dbFilename, "b");
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "--set-key-file", firstKeyFile.fileName()});
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray(""));
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
db = readDatabase(dbFilename, "b");
|
||||||
|
QVERIFY(db.isNull());
|
||||||
|
db = readDatabase(dbFilename, "b", firstKeyFile.fileName());
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd,
|
||||||
|
{"db-edit", dbFilename, "-k", firstKeyFile.fileName(), "--set-key-file", secondKeyFile.fileName()});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
db = readDatabase(dbFilename, "b", firstKeyFile.fileName());
|
||||||
|
QVERIFY(db.isNull());
|
||||||
|
db = readDatabase(dbFilename, "b", secondKeyFile.fileName());
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-k", secondKeyFile.fileName(), "--unset-password"});
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray(""));
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
execCmd(editCmd,
|
||||||
|
{"db-edit",
|
||||||
|
dbFilename,
|
||||||
|
"--no-password",
|
||||||
|
"-k",
|
||||||
|
secondKeyFile.fileName(),
|
||||||
|
"--set-key-file",
|
||||||
|
firstKeyFile.fileName()});
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray(""));
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
setInput({"b", "b"});
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-k", firstKeyFile.fileName(), "--no-password", "--set-password"});
|
||||||
|
// Skipping over the password setting prompts.
|
||||||
|
m_stderr->readLine();
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray(""));
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-k", firstKeyFile.fileName(), "--unset-key-file"});
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readAll(), QByteArray(""));
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray("Successfully edited the database.\n"));
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
db = readDatabase(dbFilename, "b", firstKeyFile.fileName());
|
||||||
|
QVERIFY(db.isNull());
|
||||||
|
db = readDatabase(dbFilename, "b");
|
||||||
|
QVERIFY(!db.isNull());
|
||||||
|
|
||||||
|
// Trying to remove the key file when there is none set should
|
||||||
|
// raise an error.
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "-p", "--unset-key-file"});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray(""));
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readLine(), QByteArray("Cannot remove file key: The database does not have a file key.\n"));
|
||||||
|
QCOMPARE(m_stderr->readLine(), QByteArray("Could not change the database key.\n"));
|
||||||
|
|
||||||
|
setInput("b");
|
||||||
|
execCmd(editCmd, {"db-edit", dbFilename, "--unset-password"});
|
||||||
|
QCOMPARE(m_stdout->readAll(), QByteArray(""));
|
||||||
|
// Skipping the password prompt.
|
||||||
|
m_stderr->readLine();
|
||||||
|
QCOMPARE(m_stderr->readLine(), QByteArray("Cannot remove all the keys from a database.\n"));
|
||||||
|
}
|
||||||
|
|
||||||
void TestCli::testInfo()
|
void TestCli::testInfo()
|
||||||
{
|
{
|
||||||
Info infoCmd;
|
DatabaseInfo infoCmd;
|
||||||
QVERIFY(!infoCmd.name.isEmpty());
|
QVERIFY(!infoCmd.name.isEmpty());
|
||||||
QVERIFY(infoCmd.getDescriptionLine().contains(infoCmd.name));
|
QVERIFY(infoCmd.getDescriptionLine().contains(infoCmd.name));
|
||||||
|
|
||||||
@ -1613,7 +1752,7 @@ void TestCli::testMerge()
|
|||||||
|
|
||||||
void TestCli::testMergeWithKeys()
|
void TestCli::testMergeWithKeys()
|
||||||
{
|
{
|
||||||
Create createCmd;
|
DatabaseCreate createCmd;
|
||||||
QVERIFY(!createCmd.name.isEmpty());
|
QVERIFY(!createCmd.name.isEmpty());
|
||||||
QVERIFY(createCmd.getDescriptionLine().contains(createCmd.name));
|
QVERIFY(createCmd.getDescriptionLine().contains(createCmd.name));
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ private slots:
|
|||||||
void testCommandParsing_data();
|
void testCommandParsing_data();
|
||||||
void testCommandParsing();
|
void testCommandParsing();
|
||||||
void testCreate();
|
void testCreate();
|
||||||
|
void testDatabaseEdit();
|
||||||
void testDiceware();
|
void testDiceware();
|
||||||
void testEdit();
|
void testEdit();
|
||||||
void testEstimate_data();
|
void testEstimate_data();
|
||||||
|
Loading…
Reference in New Issue
Block a user