diff --git a/src/cli/Clip.cpp b/src/cli/Clip.cpp index ab12bb1bcc..d50b32f0c5 100644 --- a/src/cli/Clip.cpp +++ b/src/cli/Clip.cpp @@ -22,16 +22,13 @@ #include "Clip.h" -#include #include -#include #include #include "cli/Utils.h" #include "core/Database.h" #include "core/Entry.h" #include "core/Group.h" -#include "gui/UnlockDatabaseDialog.h" Clip::Clip() { @@ -43,24 +40,19 @@ Clip::~Clip() { } -int Clip::execute(int argc, char** argv) +int Clip::execute(QStringList arguments) { - QStringList arguments; - // Skipping the first argument (keepassxc). - for (int i = 1; i < argc; ++i) { - arguments << QString(argv[i]); - } QTextStream out(stdout); - QApplication app(argc, argv); QCommandLineParser parser; parser.setApplicationDescription(this->description); parser.addPositionalArgument("database", QObject::tr("Path of the database.")); - QCommandLineOption guiPrompt(QStringList() << "g" - << "gui-prompt", - QObject::tr("Use a GUI prompt unlocking the database.")); - parser.addOption(guiPrompt); + QCommandLineOption keyFile(QStringList() << "k" + << "key-file", + QObject::tr("Key file of the database."), + QObject::tr("path")); + parser.addOption(keyFile); parser.addPositionalArgument("entry", QObject::tr("Path of the entry to clip.")); parser.addPositionalArgument( "timeout", @@ -74,16 +66,11 @@ int Clip::execute(int argc, char** argv) return EXIT_FAILURE; } - Database* db = nullptr; - if (parser.isSet("gui-prompt")) { - db = UnlockDatabaseDialog::openDatabasePrompt(args.at(0)); - } else { - db = Database::unlockFromStdin(args.at(0)); - } - + Database* db = Database::unlockFromStdin(args.at(0), parser.value(keyFile)); if (!db) { return EXIT_FAILURE; } + return this->clipEntry(db, args.at(1), args.value(2)); } diff --git a/src/cli/Clip.h b/src/cli/Clip.h index 1771e55813..a9e24faeee 100644 --- a/src/cli/Clip.h +++ b/src/cli/Clip.h @@ -25,7 +25,7 @@ class Clip : public Command public: Clip(); ~Clip(); - int execute(int argc, char** argv); + int execute(QStringList arguments); int clipEntry(Database* database, QString entryPath, QString timeout); }; diff --git a/src/cli/Command.cpp b/src/cli/Command.cpp index 443208c7e4..a7b6bab0ad 100644 --- a/src/cli/Command.cpp +++ b/src/cli/Command.cpp @@ -35,7 +35,7 @@ Command::~Command() { } -int Command::execute(int, char**) +int Command::execute(QStringList) { return EXIT_FAILURE; } diff --git a/src/cli/Command.h b/src/cli/Command.h index adc4aad0d2..b751c4a8e0 100644 --- a/src/cli/Command.h +++ b/src/cli/Command.h @@ -29,7 +29,7 @@ class Command { public: virtual ~Command(); - virtual int execute(int argc, char** argv); + virtual int execute(QStringList arguments); QString name; QString description; QString getDescriptionLine(); diff --git a/src/cli/EntropyMeter.cpp b/src/cli/EntropyMeter.cpp index 62bd973f83..1632fe2340 100644 --- a/src/cli/EntropyMeter.cpp +++ b/src/cli/EntropyMeter.cpp @@ -97,17 +97,18 @@ static void calculate(const char *pwd, int advanced) } } -int EntropyMeter::execute(int argc, char **argv) +int EntropyMeter::execute(QStringList arguments) { printf("KeePassXC Entropy Meter, based on zxcvbn-c.\nEnter your password below or pass it as argv\n"); printf(" Usage: entropy-meter [-a] [pwd1 pwd2 ...]\n> "); - int i, advanced; - if ((argc > 1) && (argv[1][0] == '-') && (!strcmp(argv[1], "-a"))) + int i, advanced = 0; + if (arguments.size() > 1 && arguments.at(1) == "-a") { advanced = 1; + arguments.removeAt(1); } - i = 2; - if (i >= argc) + i = 1; + if (i >= arguments.size()) { /* No test passwords on command line, so get them from stdin */ char line[500]; @@ -131,9 +132,9 @@ int EntropyMeter::execute(int argc, char **argv) else { /* Do the test passwords on the command line */ - for(; i < argc; ++i) + for(; i < arguments.size(); ++i) { - calculate(argv[i],advanced); + calculate(arguments.at(i).toLatin1(), advanced); } } return 0; diff --git a/src/cli/EntropyMeter.h b/src/cli/EntropyMeter.h index b1508f172a..614e2de358 100644 --- a/src/cli/EntropyMeter.h +++ b/src/cli/EntropyMeter.h @@ -25,7 +25,7 @@ class EntropyMeter : public Command public: EntropyMeter(); ~EntropyMeter(); - int execute(int argc, char** argv); + int execute(QStringList arguments); }; #endif // KEEPASSXC_ENTROPYMETER_H diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index 2095c177e3..a387686e29 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -21,15 +21,14 @@ #include "Extract.h" #include -#include #include -#include #include #include "cli/Utils.h" #include "core/Database.h" #include "format/KeePass2Reader.h" #include "keys/CompositeKey.h" +#include "keys/PasswordKey.h" Extract::Extract() { @@ -41,15 +40,8 @@ Extract::~Extract() { } -int Extract::execute(int argc, char** argv) +int Extract::execute(QStringList arguments) { - QStringList arguments; - // Skipping the first argument (keepassxc). - for (int i = 1; i < argc; ++i) { - arguments << QString(argv[i]); - } - - QCoreApplication app(argc, argv); QTextStream out(stdout); QCommandLineParser parser; @@ -66,8 +58,12 @@ int Extract::execute(int argc, char** argv) out << "Insert the database password\n> "; out.flush(); + CompositeKey compositeKey; + QString line = Utils::getPassword(); - CompositeKey key = CompositeKey::readFromLine(line); + PasswordKey passwordKey; + passwordKey.setPassword(line); + compositeKey.addKey(passwordKey); QString databaseFilename = args.at(0); QFile dbFile(databaseFilename); @@ -82,7 +78,7 @@ int Extract::execute(int argc, char** argv) KeePass2Reader reader; reader.setSaveXml(true); - Database* db = reader.readDatabase(&dbFile, key); + Database* db = reader.readDatabase(&dbFile, compositeKey); delete db; QByteArray xmlData = reader.xmlData(); diff --git a/src/cli/Extract.h b/src/cli/Extract.h index eadbb9e346..bef6a78215 100644 --- a/src/cli/Extract.h +++ b/src/cli/Extract.h @@ -25,7 +25,7 @@ class Extract : public Command public: Extract(); ~Extract(); - int execute(int argc, char** argv); + int execute(QStringList arguments); }; #endif // KEEPASSXC_EXTRACT_H diff --git a/src/cli/List.cpp b/src/cli/List.cpp index f3f22f6e34..63e48ee229 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -20,16 +20,12 @@ #include "List.h" -#include #include -#include -#include #include #include "core/Database.h" #include "core/Entry.h" #include "core/Group.h" -#include "gui/UnlockDatabaseDialog.h" List::List() { @@ -41,14 +37,8 @@ List::~List() { } -int List::execute(int argc, char** argv) +int List::execute(QStringList arguments) { - QStringList arguments; - // Skipping the first argument (keepassxc). - for (int i = 1; i < argc; ++i) { - arguments << QString(argv[i]); - } - QTextStream out(stdout); QCommandLineParser parser; @@ -56,28 +46,20 @@ int List::execute(int argc, char** argv) parser.addPositionalArgument("database", QObject::tr("Path of the database.")); parser.addPositionalArgument( "group", QObject::tr("Path of the group to list. Default is /"), QString("[group]")); - QCommandLineOption guiPrompt(QStringList() << "g" - << "gui-prompt", - QObject::tr("Use a GUI prompt unlocking the database.")); - parser.addOption(guiPrompt); + QCommandLineOption keyFile(QStringList() << "k" + << "key-file", + QObject::tr("Key file of the database."), + QObject::tr("path")); + parser.addOption(keyFile); parser.process(arguments); const QStringList args = parser.positionalArguments(); if (args.size() != 1 && args.size() != 2) { - QCoreApplication app(argc, argv); out << parser.helpText().replace("keepassxc-cli", "keepassxc-cli ls"); return EXIT_FAILURE; } - Database* db = nullptr; - if (parser.isSet("gui-prompt")) { - QApplication app(argc, argv); - db = UnlockDatabaseDialog::openDatabasePrompt(args.at(0)); - } else { - QCoreApplication app(argc, argv); - db = Database::unlockFromStdin(args.at(0)); - } - + Database* db = Database::unlockFromStdin(args.at(0), parser.value(keyFile)); if (db == nullptr) { return EXIT_FAILURE; } diff --git a/src/cli/List.h b/src/cli/List.h index cd9f8d1df9..d12105f3c2 100644 --- a/src/cli/List.h +++ b/src/cli/List.h @@ -25,7 +25,7 @@ class List : public Command public: List(); ~List(); - int execute(int argc, char** argv); + int execute(QStringList arguments); int listGroup(Database* database, QString groupPath = QString("")); }; diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index 7567029c62..a713cbb33a 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -19,14 +19,10 @@ #include "Merge.h" -#include #include -#include -#include #include #include "core/Database.h" -#include "gui/UnlockDatabaseDialog.h" Merge::Merge() { @@ -38,14 +34,8 @@ Merge::~Merge() { } -int Merge::execute(int argc, char** argv) +int Merge::execute(QStringList arguments) { - QStringList arguments; - // Skipping the first argument (keepassxc). - for (int i = 1; i < argc; ++i) { - arguments << QString(argv[i]); - } - QTextStream out(stdout); QCommandLineParser parser; @@ -55,52 +45,47 @@ int Merge::execute(int argc, char** argv) QCommandLineOption samePasswordOption( QStringList() << "s" - << "same-password", - QObject::tr("Use the same password for both database files.")); - - QCommandLineOption guiPrompt(QStringList() << "g" - << "gui-prompt", - QObject::tr("Use a GUI prompt unlocking the database.")); - parser.addOption(guiPrompt); + << "same-credentials", + QObject::tr("Use the same credentials for both database files.")); + + QCommandLineOption keyFile(QStringList() << "k" + << "key-file", + QObject::tr("Key file of the database."), + QObject::tr("path")); + parser.addOption(keyFile); + QCommandLineOption keyFileFrom(QStringList() << "f" + << "key-file-from", + QObject::tr("Key file of the database to merge from."), + QObject::tr("path")); + parser.addOption(keyFileFrom); parser.addOption(samePasswordOption); parser.process(arguments); const QStringList args = parser.positionalArguments(); if (args.size() != 2) { - QCoreApplication app(argc, argv); out << parser.helpText().replace("keepassxc-cli", "keepassxc-cli merge"); return EXIT_FAILURE; } - Database* db1; - Database* db2; - if (parser.isSet("gui-prompt")) { - QApplication app(argc, argv); - db1 = UnlockDatabaseDialog::openDatabasePrompt(args.at(0)); - if (!parser.isSet("same-password")) { - db2 = UnlockDatabaseDialog::openDatabasePrompt(args.at(1)); - } else { - db2 = Database::openDatabaseFile(args.at(1), *(db1->key().clone())); - } - } else { - QCoreApplication app(argc, argv); - db1 = Database::unlockFromStdin(args.at(0)); - if (!parser.isSet("same-password")) { - db2 = Database::unlockFromStdin(args.at(1)); - } else { - db2 = Database::openDatabaseFile(args.at(1), *(db1->key().clone())); - } - } + Database* db1 = Database::unlockFromStdin(args.at(0), parser.value(keyFile)); if (db1 == nullptr) { return EXIT_FAILURE; } + + Database* db2; + if (!parser.isSet("same-credentials")) { + db2 = Database::unlockFromStdin(args.at(1), parser.value(keyFileFrom)); + } else { + db2 = Database::openDatabaseFile(args.at(1), *(db1->key().clone())); + } if (db2 == nullptr) { return EXIT_FAILURE; } db1->merge(db2); + QString errorMessage = db1->saveToFile(args.at(0)); if (!errorMessage.isEmpty()) { qCritical("Unable to save database to file : %s", qPrintable(errorMessage)); diff --git a/src/cli/Merge.h b/src/cli/Merge.h index bb121f579e..4f0b428368 100644 --- a/src/cli/Merge.h +++ b/src/cli/Merge.h @@ -25,7 +25,7 @@ class Merge : public Command public: Merge(); ~Merge(); - int execute(int argc, char** argv); + int execute(QStringList arguments); }; #endif // KEEPASSXC_MERGE_H diff --git a/src/cli/Show.cpp b/src/cli/Show.cpp index 55da875152..d137f74dfd 100644 --- a/src/cli/Show.cpp +++ b/src/cli/Show.cpp @@ -21,8 +21,6 @@ #include "Show.h" #include -#include -#include #include #include "core/Database.h" @@ -39,20 +37,18 @@ Show::~Show() { } -int Show::execute(int argc, char** argv) +int Show::execute(QStringList arguments) { - QStringList arguments; - // Skipping the first argument (keepassxc). - for (int i = 1; i < argc; ++i) { - arguments << QString(argv[i]); - } - - QCoreApplication app(argc, argv); QTextStream out(stdout); QCommandLineParser parser; parser.setApplicationDescription(this->description); parser.addPositionalArgument("database", QObject::tr("Path of the database.")); + QCommandLineOption keyFile(QStringList() << "k" + << "key-file", + QObject::tr("Key file of the database."), + QObject::tr("path")); + parser.addOption(keyFile); parser.addPositionalArgument("entry", QObject::tr("Name of the entry to show.")); parser.process(arguments); @@ -62,7 +58,7 @@ int Show::execute(int argc, char** argv) return EXIT_FAILURE; } - Database* db = Database::unlockFromStdin(args.at(0)); + Database* db = Database::unlockFromStdin(args.at(0), parser.value(keyFile)); if (db == nullptr) { return EXIT_FAILURE; } diff --git a/src/cli/Show.h b/src/cli/Show.h index b10e6bf0a1..f3bc55e606 100644 --- a/src/cli/Show.h +++ b/src/cli/Show.h @@ -25,7 +25,7 @@ class Show : public Command public: Show(); ~Show(); - int execute(int argc, char** argv); + int execute(QStringList arguments); int showEntry(Database* database, QString entryPath); }; diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 37210b6a1b..1462f92b91 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -43,6 +43,9 @@ int main(int argc, char** argv) return EXIT_FAILURE; } + QCoreApplication app(argc, argv); + app.setApplicationVersion(KEEPASSX_VERSION); + QTextStream out(stdout); QStringList arguments; for (int i = 0; i < argc; ++i) { @@ -67,8 +70,6 @@ int main(int argc, char** argv) parser.parse(arguments); if (parser.positionalArguments().size() < 1) { - QCoreApplication app(argc, argv); - app.setApplicationVersion(KEEPASSX_VERSION); if (parser.isSet("version")) { // Switch to parser.showVersion() when available (QT 5.4). out << KEEPASSX_VERSION << endl; @@ -82,14 +83,14 @@ int main(int argc, char** argv) if (command == nullptr) { qCritical("Invalid command %s.", qPrintable(commandName)); - QCoreApplication app(argc, argv); - app.setApplicationVersion(KEEPASSX_VERSION); // showHelp exits the application immediately, so we need to set the // exit code here. parser.showHelp(EXIT_FAILURE); } - int exitCode = command->execute(argc, argv); + // Removing the first argument (keepassxc). + arguments.removeFirst(); + int exitCode = command->execute(arguments); #if defined(WITH_ASAN) && defined(WITH_LSAN) // do leak check here to prevent massive tail of end-of-process leak errors from third-party libraries diff --git a/src/core/Database.cpp b/src/core/Database.cpp index b0b215eb68..fdfc11cfea 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -31,6 +31,9 @@ #include "format/KeePass2.h" #include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" +#include "keys/PasswordKey.h" +#include "keys/FileKey.h" +#include "keys/CompositeKey.h" QHash Database::m_uuidMap; @@ -397,16 +400,27 @@ Database* Database::openDatabaseFile(QString fileName, CompositeKey key) return db; } -Database* Database::unlockFromStdin(QString databaseFilename) +Database* Database::unlockFromStdin(QString databaseFilename, QString keyFilename) { QTextStream outputTextStream(stdout); outputTextStream << QString("Insert password to unlock " + databaseFilename + "\n> "); outputTextStream.flush(); + CompositeKey compositeKey; + QString line = Utils::getPassword(); - CompositeKey key = CompositeKey::readFromLine(line); - return Database::openDatabaseFile(databaseFilename, key); + PasswordKey passwordKey; + passwordKey.setPassword(line); + compositeKey.addKey(passwordKey); + + if (!keyFilename.isEmpty()) { + FileKey fileKey; + fileKey.load(keyFilename); + compositeKey.addKey(fileKey); + } + + return Database::openDatabaseFile(databaseFilename, compositeKey); } QString Database::saveToFile(QString filePath) diff --git a/src/core/Database.h b/src/core/Database.h index a799e0b3bf..2ab556a07a 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -122,7 +122,7 @@ class Database : public QObject static Database* databaseByUuid(const Uuid& uuid); static Database* openDatabaseFile(QString fileName, CompositeKey key); - static Database* unlockFromStdin(QString databaseFilename); + static Database* unlockFromStdin(QString databaseFilename, QString keyFilename = QString("")); signals: void groupDataChanged(Group* group); diff --git a/src/gui/UnlockDatabaseDialog.cpp b/src/gui/UnlockDatabaseDialog.cpp index bf5cbdbc0d..a0c9154672 100644 --- a/src/gui/UnlockDatabaseDialog.cpp +++ b/src/gui/UnlockDatabaseDialog.cpp @@ -54,20 +54,3 @@ void UnlockDatabaseDialog::complete(bool r) reject(); } } - -Database* UnlockDatabaseDialog::openDatabasePrompt(QString databaseFilename) -{ - - UnlockDatabaseDialog* unlockDatabaseDialog = new UnlockDatabaseDialog(); - unlockDatabaseDialog->setObjectName("Open database"); - unlockDatabaseDialog->setDBFilename(databaseFilename); - unlockDatabaseDialog->show(); - unlockDatabaseDialog->exec(); - - Database* db = unlockDatabaseDialog->database(); - if (!db) { - qWarning("Could not open database %s.", qPrintable(databaseFilename)); - } - delete unlockDatabaseDialog; - return db; -} diff --git a/src/gui/UnlockDatabaseDialog.h b/src/gui/UnlockDatabaseDialog.h index 55830c97e3..9a42ed6e28 100644 --- a/src/gui/UnlockDatabaseDialog.h +++ b/src/gui/UnlockDatabaseDialog.h @@ -35,7 +35,6 @@ class UnlockDatabaseDialog : public QDialog void setDBFilename(const QString& filename); void clearForms(); Database* database(); - static Database* openDatabasePrompt(QString databaseFilename); signals: void unlockDone(bool); diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp index 3b1a82a225..83a6725c94 100644 --- a/src/keys/CompositeKey.cpp +++ b/src/keys/CompositeKey.cpp @@ -80,29 +80,6 @@ CompositeKey& CompositeKey::operator=(const CompositeKey& key) return *this; } -/* - * Read a key from a line of input. - * If the line references a valid file - * path, the key is loaded from file. - */ -CompositeKey CompositeKey::readFromLine(QString line) -{ - - CompositeKey key; - if (QFile::exists(line)) { - FileKey fileKey; - fileKey.load(line); - key.addKey(fileKey); - } - else { - PasswordKey password; - password.setPassword(line); - key.addKey(password); - } - return key; - -} - QByteArray CompositeKey::rawKey() const { CryptoHash cryptoHash(CryptoHash::Sha256); diff --git a/src/keys/CompositeKey.h b/src/keys/CompositeKey.h index 12e2d955d8..d9c4e3a9ed 100644 --- a/src/keys/CompositeKey.h +++ b/src/keys/CompositeKey.h @@ -46,7 +46,6 @@ class CompositeKey : public Key void addChallengeResponseKey(QSharedPointer key); static int transformKeyBenchmark(int msec); - static CompositeKey readFromLine(QString line); private: static QByteArray transformKeyRaw(const QByteArray& key, const QByteArray& seed, diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp index dea0436f0f..738b39a269 100644 --- a/tests/TestKeys.cpp +++ b/tests/TestKeys.cpp @@ -84,22 +84,6 @@ void TestKeys::testComposite() delete compositeKey4; } -void TestKeys::testCompositeKeyReadFromLine() -{ - - QString keyFilename = QString("%1/FileKeyXml.key").arg(QString(KEEPASSX_TEST_DATA_DIR)); - - CompositeKey compositeFileKey = CompositeKey::readFromLine(keyFilename); - FileKey fileKey; - fileKey.load(keyFilename); - QCOMPARE(compositeFileKey.rawKey().size(), fileKey.rawKey().size()); - - CompositeKey compositePasswordKey = CompositeKey::readFromLine(QString("password")); - PasswordKey passwordKey(QString("password")); - QCOMPARE(compositePasswordKey.rawKey().size(), passwordKey.rawKey().size()); - -} - void TestKeys::testFileKey() { QFETCH(QString, type); diff --git a/tests/TestKeys.h b/tests/TestKeys.h index 06ed3b0a12..1cbe7bf968 100644 --- a/tests/TestKeys.h +++ b/tests/TestKeys.h @@ -28,7 +28,6 @@ class TestKeys : public QObject private slots: void initTestCase(); void testComposite(); - void testCompositeKeyReadFromLine(); void testFileKey(); void testFileKey_data(); void testCreateFileKey();