From 52991f3d66eb5e7d7a5098dfe3b9bb7106466f52 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Mon, 30 Jan 2017 19:18:35 -0500 Subject: [PATCH 01/24] Add first keepassxc-cli version. --- src/CMakeLists.txt | 1 + {utils => src/cli}/CMakeLists.txt | 29 +++---- utils/kdbx-extract.cpp => src/cli/Extract.cpp | 9 +-- src/cli/Extract.h | 27 +++++++ utils/kdbx-merge.cpp => src/cli/Merge.cpp | 12 +-- src/cli/Merge.h | 27 +++++++ src/cli/keepassxc-cli.cpp | 77 +++++++++++++++++++ 7 files changed, 150 insertions(+), 32 deletions(-) rename {utils => src/cli}/CMakeLists.txt (58%) rename utils/kdbx-extract.cpp => src/cli/Extract.cpp (92%) create mode 100644 src/cli/Extract.h rename utils/kdbx-merge.cpp => src/cli/Merge.cpp (93%) create mode 100644 src/cli/Merge.h create mode 100644 src/cli/keepassxc-cli.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5e221b91..1d998446 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,6 +164,7 @@ if(WITH_XC_HTTP) endif() add_subdirectory(autotype) +add_subdirectory(cli) set(autotype_SOURCES core/Tools.cpp diff --git a/utils/CMakeLists.txt b/src/cli/CMakeLists.txt similarity index 58% rename from utils/CMakeLists.txt rename to src/cli/CMakeLists.txt index 83f00b4b..4456cbea 100644 --- a/utils/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2010 Felix Geyer +# Copyright (C) 2017 KeePassXC Team # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -13,24 +13,19 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -include_directories(../src) +set(cli_SOURCES + Merge.cpp + Merge.h + Extract.cpp + Extract.h) -add_executable(kdbx-extract kdbx-extract.cpp) -target_link_libraries(kdbx-extract +add_library(cli STATIC ${cli_SOURCES}) +target_link_libraries(cli Qt5::Core Qt5::Widgets) + +add_executable(keepassxc-cli keepassxc-cli.cpp) +target_link_libraries(keepassxc-cli + cli keepassx_core Qt5::Core ${GCRYPT_LIBRARIES} - ${GPGERROR_LIBRARIES} ${ZLIB_LIBRARIES}) - -add_executable(kdbx-merge kdbx-merge.cpp) -target_link_libraries(kdbx-merge - keepassx_core - Qt5::Core - ${GCRYPT_LIBRARIES} - ${GPGERROR_LIBRARIES} - ${ZLIB_LIBRARIES}) - - -add_executable(entropy-meter entropy-meter.cpp) -target_link_libraries(entropy-meter zxcvbn) diff --git a/utils/kdbx-extract.cpp b/src/cli/Extract.cpp similarity index 92% rename from utils/kdbx-extract.cpp rename to src/cli/Extract.cpp index 255f5d00..4ad65878 100644 --- a/utils/kdbx-extract.cpp +++ b/src/cli/Extract.cpp @@ -17,6 +17,8 @@ #include +#include "Extract.h" + #include #include #include @@ -30,7 +32,7 @@ #include "keys/FileKey.h" #include "keys/PasswordKey.h" -int main(int argc, char **argv) +int Extract::execute(int argc, char **argv) { QCoreApplication app(argc, argv); @@ -38,7 +40,6 @@ int main(int argc, char **argv) parser.setApplicationDescription(QCoreApplication::translate("main", "Extract and print a KeePassXC database file.")); parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database to extract.")); - parser.addHelpOption(); parser.process(app); const QStringList args = parser.positionalArguments(); @@ -47,10 +48,6 @@ int main(int argc, char **argv) return 1; } - if (!Crypto::init()) { - qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); - } - static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); QString line = inputTextStream.readLine(); CompositeKey key = CompositeKey::readFromLine(line); diff --git a/src/cli/Extract.h b/src/cli/Extract.h new file mode 100644 index 00000000..9a6638e4 --- /dev/null +++ b/src/cli/Extract.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#ifndef KEEPASSXC_EXTRACT_H +#define KEEPASSXC_EXTRACT_H + +class Extract +{ +public: + static int execute(int argc, char** argv); +}; + +#endif // KEEPASSXC_EXTRACT_H diff --git a/utils/kdbx-merge.cpp b/src/cli/Merge.cpp similarity index 93% rename from utils/kdbx-merge.cpp rename to src/cli/Merge.cpp index da780ea1..bac8f4bd 100644 --- a/utils/kdbx-merge.cpp +++ b/src/cli/Merge.cpp @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -#include +#include "Merge.h" #include #include @@ -25,12 +25,11 @@ #include #include "core/Database.h" -#include "crypto/Crypto.h" #include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" #include "keys/CompositeKey.h" -int main(int argc, char **argv) +int Merge::execute(int argc, char** argv) { QCoreApplication app(argc, argv); @@ -43,7 +42,6 @@ int main(int argc, char **argv) QCommandLineOption samePasswordOption(QStringList() << "s" << "same-password", QCoreApplication::translate("main", "use the same password for both database files.")); - parser.addHelpOption(); parser.addOption(samePasswordOption); parser.process(app); @@ -53,10 +51,6 @@ int main(int argc, char **argv) return 1; } - if (!Crypto::init()) { - qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); - } - static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); QString line1 = inputTextStream.readLine(); @@ -133,6 +127,6 @@ int main(int argc, char **argv) } qDebug("Successfully merged the database files.\n"); - return 1; + return 0; } diff --git a/src/cli/Merge.h b/src/cli/Merge.h new file mode 100644 index 00000000..dd9b8a4c --- /dev/null +++ b/src/cli/Merge.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#ifndef KEEPASSXC_MERGE_H +#define KEEPASSXC_MERGE_H + +class Merge +{ +public: + static int execute(int argc, char** argv); +}; + +#endif // KEEPASSXC_MERGE_H diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp new file mode 100644 index 00000000..086e544a --- /dev/null +++ b/src/cli/keepassxc-cli.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#include +#include + +#include +#include +#include + +#include "config-keepassx.h" +#include "crypto/Crypto.h" + +int main(int argc, char **argv) +{ + + if (!Crypto::init()) { + qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + return 1; + } + + QCoreApplication app(argc, argv); + app.setApplicationVersion(KEEPASSX_VERSION); + + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("main", "KeepassXC command line interface.")); + parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute.")); + + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if (args.size() < 1) { + parser.showHelp(); + return 1; + } + + QString commandName = args.at(0); + + for (int i = 1; i < argc - 1; ++i) { + argv[i] = argv[i+1]; + } + argv[argc - 1] = nullptr; + argc--; + + if (commandName == "merge") + { + argv[0] = const_cast("keepassxc-cli merge"); + return Merge::execute(argc, argv); + } + + if (commandName == "extract") + { + argv[0] = const_cast("keepassxc-cli extract"); + return Extract::execute(argc, argv); + } + + qCritical("Invalid command %s.", qPrintable(commandName)); + parser.showHelp(); + return 1; + +} From 9cfc862b0787567a06c330c5f72ccd7bccc3e5bd Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 10:33:50 -0500 Subject: [PATCH 02/24] Disable core dumps (keepassxc-cli). --- src/cli/keepassxc-cli.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 086e544a..78b11164 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -23,10 +23,14 @@ #include #include "config-keepassx.h" +#include "core/Tools.h" #include "crypto/Crypto.h" int main(int argc, char **argv) { +#ifdef QT_NO_DEBUG + Tools::disableCoreDumps(); +#endif if (!Crypto::init()) { qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); From bf9b23539e172f1bd3aa9e2c4d3ff44726a2115c Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 10:51:33 -0500 Subject: [PATCH 03/24] Add dependency + adjust styling. --- src/cli/CMakeLists.txt | 1 + src/cli/keepassxc-cli.cpp | 14 ++++++-------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 4456cbea..70dd420d 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -28,4 +28,5 @@ target_link_libraries(keepassxc-cli keepassx_core Qt5::Core ${GCRYPT_LIBRARIES} + ${GPGERROR_LIBRARIES} ${ZLIB_LIBRARIES}) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 78b11164..7df4d7d8 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -57,20 +57,18 @@ int main(int argc, char **argv) QString commandName = args.at(0); for (int i = 1; i < argc - 1; ++i) { - argv[i] = argv[i+1]; + argv[i] = argv[i + 1]; } argv[argc - 1] = nullptr; - argc--; + --argc; - if (commandName == "merge") - { - argv[0] = const_cast("keepassxc-cli merge"); + if (commandName == "merge") { + argv[0] = const_cast("keepassxc-cli merge"); return Merge::execute(argc, argv); } - if (commandName == "extract") - { - argv[0] = const_cast("keepassxc-cli extract"); + if (commandName == "extract") { + argv[0] = const_cast("keepassxc-cli extract"); return Extract::execute(argc, argv); } From 9b92e7f8e8fe6438f7916832ede22bdb9b22bdae Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 17:30:54 -0500 Subject: [PATCH 04/24] Use EXIT_FAILURE/SUCCESS --- src/cli/Extract.cpp | 11 ++++++----- src/cli/Merge.cpp | 24 +++++++++++++----------- src/cli/keepassxc-cli.cpp | 11 ++++++----- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index 4ad65878..73581d8f 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include "Extract.h" @@ -45,7 +46,7 @@ int Extract::execute(int argc, char **argv) const QStringList args = parser.positionalArguments(); if (args.size() != 1) { parser.showHelp(); - return 1; + return EXIT_FAILURE; } static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); @@ -56,11 +57,11 @@ int Extract::execute(int argc, char **argv) QFile dbFile(databaseFilename); if (!dbFile.exists()) { qCritical("File %s does not exist.", qPrintable(databaseFilename)); - return 1; + return EXIT_FAILURE; } if (!dbFile.open(QIODevice::ReadOnly)) { qCritical("Unable to open file %s.", qPrintable(databaseFilename)); - return 1; + return EXIT_FAILURE; } KeePass2Reader reader; @@ -73,15 +74,15 @@ int Extract::execute(int argc, char **argv) if (reader.hasError()) { if (xmlData.isEmpty()) { qCritical("Error while reading the database:\n%s", qPrintable(reader.errorString())); - return 1; } else { qWarning("Error while parsing the database:\n%s\n", qPrintable(reader.errorString())); } + return EXIT_FAILURE; } QTextStream out(stdout); out << xmlData.constData() << "\n"; - return 0; + return EXIT_SUCCESS; } diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index bac8f4bd..caa8d19c 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +#include + #include "Merge.h" #include @@ -48,7 +50,7 @@ int Merge::execute(int argc, char** argv) const QStringList args = parser.positionalArguments(); if (args.size() != 2) { parser.showHelp(); - return 1; + return EXIT_FAILURE; } static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); @@ -70,11 +72,11 @@ int Merge::execute(int argc, char** argv) QFile dbFile1(databaseFilename1); if (!dbFile1.exists()) { qCritical("File %s does not exist.", qPrintable(databaseFilename1)); - return 1; + return EXIT_FAILURE; } if (!dbFile1.open(QIODevice::ReadOnly)) { qCritical("Unable to open file %s.", qPrintable(databaseFilename1)); - return 1; + return EXIT_FAILURE; } KeePass2Reader reader1; @@ -82,7 +84,7 @@ int Merge::execute(int argc, char** argv) if (reader1.hasError()) { qCritical("Error while parsing the database:\n%s\n", qPrintable(reader1.errorString())); - return 1; + return EXIT_FAILURE; } @@ -90,11 +92,11 @@ int Merge::execute(int argc, char** argv) QFile dbFile2(databaseFilename2); if (!dbFile2.exists()) { qCritical("File %s does not exist.", qPrintable(databaseFilename2)); - return 1; + return EXIT_FAILURE; } if (!dbFile2.open(QIODevice::ReadOnly)) { qCritical("Unable to open file %s.", qPrintable(databaseFilename2)); - return 1; + return EXIT_FAILURE; } KeePass2Reader reader2; @@ -102,7 +104,7 @@ int Merge::execute(int argc, char** argv) if (reader2.hasError()) { qCritical("Error while parsing the database:\n%s\n", qPrintable(reader2.errorString())); - return 1; + return EXIT_FAILURE; } db1->merge(db2); @@ -110,7 +112,7 @@ int Merge::execute(int argc, char** argv) QSaveFile saveFile(databaseFilename1); if (!saveFile.open(QIODevice::WriteOnly)) { qCritical("Unable to open file %s for writing.", qPrintable(databaseFilename1)); - return 1; + return EXIT_FAILURE; } KeePass2Writer writer; @@ -118,15 +120,15 @@ int Merge::execute(int argc, char** argv) if (writer.hasError()) { qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString())); - return 1; + return EXIT_FAILURE; } if (!saveFile.commit()) { qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString())); - return 0; + return EXIT_FAILURE; } qDebug("Successfully merged the database files.\n"); - return 0; + return EXIT_SUCCESS; } diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 7df4d7d8..e745dd09 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -15,13 +15,14 @@ * along with this program. If not, see . */ -#include -#include +#include #include #include #include +#include +#include #include "config-keepassx.h" #include "core/Tools.h" #include "crypto/Crypto.h" @@ -34,7 +35,7 @@ int main(int argc, char **argv) if (!Crypto::init()) { qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); - return 1; + return EXIT_FAILURE; } QCoreApplication app(argc, argv); @@ -51,7 +52,7 @@ int main(int argc, char **argv) const QStringList args = parser.positionalArguments(); if (args.size() < 1) { parser.showHelp(); - return 1; + return EXIT_FAILURE; } QString commandName = args.at(0); @@ -74,6 +75,6 @@ int main(int argc, char **argv) qCritical("Invalid command %s.", qPrintable(commandName)); parser.showHelp(); - return 1; + return EXIT_FAILURE; } From 992d8a90c746f31ba77ada572d1e1c88ab299d79 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 17:54:39 -0500 Subject: [PATCH 05/24] Migrate entropy-meter to keepassxc-cli --- CMakeLists.txt | 1 - src/cli/CMakeLists.txt | 2 ++ .../cli/EntropyMeter.cpp | 4 ++- src/cli/EntropyMeter.h | 27 +++++++++++++++++++ src/cli/keepassxc-cli.cpp | 16 ++++++++--- 5 files changed, 44 insertions(+), 6 deletions(-) rename utils/entropy-meter.cpp => src/cli/EntropyMeter.cpp (98%) create mode 100644 src/cli/EntropyMeter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e7d22312..3dd43555 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -254,7 +254,6 @@ include(FeatureSummary) add_subdirectory(src) add_subdirectory(share) -add_subdirectory(utils) if(WITH_TESTS) add_subdirectory(tests) endif(WITH_TESTS) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 70dd420d..d678ff39 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -16,6 +16,8 @@ set(cli_SOURCES Merge.cpp Merge.h + EntropyMeter.cpp + EntropyMeter.h Extract.cpp Extract.h) diff --git a/utils/entropy-meter.cpp b/src/cli/EntropyMeter.cpp similarity index 98% rename from utils/entropy-meter.cpp rename to src/cli/EntropyMeter.cpp index 74f6bc11..ffaecc8e 100644 --- a/utils/entropy-meter.cpp +++ b/src/cli/EntropyMeter.cpp @@ -6,6 +6,8 @@ Copyright (c) 2016, KeePassXC Team See zxcvbn/zxcvbn.cpp for complete COPYRIGHT Notice */ +#include "EntropyMeter.h" + #include #include #include @@ -76,7 +78,7 @@ static void calculate(const char *pwd, int advanced) } } -int main(int argc, char **argv) +int EntropyMeter::execute(int argc, char **argv) { 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> "); diff --git a/src/cli/EntropyMeter.h b/src/cli/EntropyMeter.h new file mode 100644 index 00000000..5034b966 --- /dev/null +++ b/src/cli/EntropyMeter.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#ifndef KEEPASSXC_ENTROPYMETER_H +#define KEEPASSXC_ENTROPYMETER_H + +class EntropyMeter +{ +public: + static int execute(int argc, char** argv); +}; + +#endif // KEEPASSXC_ENTROPYMETER_H diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index e745dd09..e8719d9c 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -23,6 +23,7 @@ #include #include +#include #include "config-keepassx.h" #include "core/Tools.h" #include "crypto/Crypto.h" @@ -47,15 +48,17 @@ int main(int argc, char **argv) parser.addHelpOption(); parser.addVersionOption(); - parser.process(app); + // TODO : use process once the setOptionsAfterPositionalArgumentsMode (Qt 5.6) + // is available. Until then, options passed to sub-commands won't be + // recognized by this parser. + // parser.process(app); - const QStringList args = parser.positionalArguments(); - if (args.size() < 1) { + if (argc < 2) { parser.showHelp(); return EXIT_FAILURE; } - QString commandName = args.at(0); + QString commandName = argv[1]; for (int i = 1; i < argc - 1; ++i) { argv[i] = argv[i + 1]; @@ -73,6 +76,11 @@ int main(int argc, char **argv) return Extract::execute(argc, argv); } + if (commandName == "entropy-meter") { + argv[0] = const_cast("keepassxc-cli entropy-meter"); + return EntropyMeter::execute(argc, argv); + } + qCritical("Invalid command %s.", qPrintable(commandName)); parser.showHelp(); return EXIT_FAILURE; From 342d49d05048330d07f7062bcf989df5f9c8b21a Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 17:59:06 -0500 Subject: [PATCH 06/24] Missing zxcvbn dependency. --- src/cli/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index d678ff39..8b547636 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -31,4 +31,5 @@ target_link_libraries(keepassxc-cli Qt5::Core ${GCRYPT_LIBRARIES} ${GPGERROR_LIBRARIES} - ${ZLIB_LIBRARIES}) + ${ZLIB_LIBRARIES} + zxcvbn) From 805600ad448bb129f745bfded33d18adc86a714e Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 2 Feb 2017 18:29:31 -0500 Subject: [PATCH 07/24] Installing keepassxc-cli executable. --- src/cli/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 8b547636..b8dce663 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -33,3 +33,7 @@ target_link_libraries(keepassxc-cli ${GPGERROR_LIBRARIES} ${ZLIB_LIBRARIES} zxcvbn) + +install(TARGETS keepassxc-cli + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT Runtime) From e1e8f33f6776a82302f4fb64b7d69851407c0873 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sat, 4 Feb 2017 14:52:43 -0500 Subject: [PATCH 08/24] Install path on Mac. --- CMakeLists.txt | 3 +++ src/cli/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dd43555..56baa8f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -166,16 +166,19 @@ if(APPLE AND "${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr/local") endif() if(MINGW) + set(CLI_INSTALL_DIR ".") set(BIN_INSTALL_DIR ".") set(PLUGIN_INSTALL_DIR ".") set(DATA_INSTALL_DIR "share") elseif(APPLE) + set(CLI_INSTALL_DIR "/usr/local/bin") set(BIN_INSTALL_DIR ".") set(PLUGIN_INSTALL_DIR "${PROGNAME}.app/Contents/PlugIns") set(DATA_INSTALL_DIR "${PROGNAME}.app/Contents/Resources") else() include(GNUInstallDirs) + set(CLI_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") set(BIN_INSTALL_DIR "${CMAKE_INSTALL_BINDIR}") set(PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/keepassxc") set(DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/keepassxc") diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index b8dce663..4f0386e3 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -36,4 +36,4 @@ target_link_libraries(keepassxc-cli install(TARGETS keepassxc-cli BUNDLE DESTINATION . COMPONENT Runtime - RUNTIME DESTINATION ${BIN_INSTALL_DIR} COMPONENT Runtime) + RUNTIME DESTINATION ${CLI_INSTALL_DIR} COMPONENT Runtime) From 782d1f17d1d4c57ac940655ab48481de2ede5ed1 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 5 Feb 2017 12:56:44 -0500 Subject: [PATCH 09/24] Using ++argv --- src/cli/keepassxc-cli.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index e8719d9c..e532e95f 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -60,10 +60,8 @@ int main(int argc, char **argv) QString commandName = argv[1]; - for (int i = 1; i < argc - 1; ++i) { - argv[i] = argv[i + 1]; - } - argv[argc - 1] = nullptr; + // Removing the first cli argument before dispatching. + ++argv; --argc; if (commandName == "merge") { From b85941531df219cdc5547445df7e91318c026c3f Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 5 Feb 2017 13:40:40 -0500 Subject: [PATCH 10/24] Keepass -> KeePass. --- src/cli/keepassxc-cli.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index e532e95f..a7e7c275 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -43,7 +43,7 @@ int main(int argc, char **argv) app.setApplicationVersion(KEEPASSX_VERSION); QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", "KeepassXC command line interface.")); + parser.setApplicationDescription(QCoreApplication::translate("main", "KeePassXC command line interface.")); parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute.")); parser.addHelpOption(); From 7636a559f9408ee765665c9e94527bf9c63c0d21 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Mon, 13 Feb 2017 22:21:19 -0500 Subject: [PATCH 11/24] Remove unused imports. --- src/cli/Extract.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index 73581d8f..b08039ae 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -27,11 +27,8 @@ #include #include "core/Database.h" -#include "crypto/Crypto.h" #include "format/KeePass2Reader.h" #include "keys/CompositeKey.h" -#include "keys/FileKey.h" -#include "keys/PasswordKey.h" int Extract::execute(int argc, char **argv) { From 7ca475f968deba1a659c0b03235afe806a2016bf Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Mon, 13 Feb 2017 22:29:20 -0500 Subject: [PATCH 12/24] Add list to keepassxc-cli --- src/cli/CMakeLists.txt | 2 + src/cli/List.cpp | 101 ++++++++++++++++++++++++++++++++++++++ src/cli/List.h | 27 ++++++++++ src/cli/keepassxc-cli.cpp | 6 +++ 4 files changed, 136 insertions(+) create mode 100644 src/cli/List.cpp create mode 100644 src/cli/List.h diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 4f0386e3..0ed5d991 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -14,6 +14,8 @@ # along with this program. If not, see . set(cli_SOURCES + List.cpp + List.h Merge.cpp Merge.h EntropyMeter.cpp diff --git a/src/cli/List.cpp b/src/cli/List.cpp new file mode 100644 index 00000000..2049cc1d --- /dev/null +++ b/src/cli/List.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#include +#include + +#include "List.h" + +#include +#include +#include +#include +#include + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "format/KeePass2Reader.h" +#include "keys/CompositeKey.h" + +void printGroup(Group* group, QString baseName, int depth) { + + QTextStream out(stdout); + + QString groupName = baseName + group->name() + "/"; + QString indentation = QString(" ").repeated(depth); + + out << indentation << groupName << "\n"; + out.flush(); + + if (group->entries().isEmpty() && group->children().isEmpty()) { + out << indentation << " [empty]\n"; + return; + } + + for (Entry* entry : group->entries()) { + out << indentation << " " << entry->title() << " " << entry->uuid().toHex() << "\n"; + } + + for (Group* innerGroup : group->children()) { + printGroup(innerGroup, groupName, depth + 1); + } + +} + +int List::execute(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("main", + "List the passwords in the database.")); + parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database.")); + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if (args.size() != 1) { + parser.showHelp(); + return EXIT_FAILURE; + } + + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); + QString line = inputTextStream.readLine(); + CompositeKey key = CompositeKey::readFromLine(line); + + QString databaseFilename = args.at(0); + QFile dbFile(databaseFilename); + if (!dbFile.exists()) { + qCritical("File %s does not exist.", qPrintable(databaseFilename)); + return EXIT_FAILURE; + } + if (!dbFile.open(QIODevice::ReadOnly)) { + qCritical("Unable to open file %s.", qPrintable(databaseFilename)); + return EXIT_FAILURE; + } + + KeePass2Reader reader; + Database* db = reader.readDatabase(&dbFile, key); + + if (reader.hasError()) { + qCritical("Error while parsing the database:\n%s\n", qPrintable(reader.errorString())); + return EXIT_FAILURE; + } + + printGroup(db->rootGroup(), QString(""), 0); + return EXIT_SUCCESS; +} diff --git a/src/cli/List.h b/src/cli/List.h new file mode 100644 index 00000000..76f086c6 --- /dev/null +++ b/src/cli/List.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#ifndef KEEPASSXC_LIST_H +#define KEEPASSXC_LIST_H + +class List +{ +public: + static int execute(int argc, char** argv); +}; + +#endif // KEEPASSXC_LIST_H diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index a7e7c275..67eb8e8a 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,11 @@ int main(int argc, char **argv) ++argv; --argc; + if (commandName == "list") { + argv[0] = const_cast("keepassxc-cli list"); + return List::execute(argc, argv); + } + if (commandName == "merge") { argv[0] = const_cast("keepassxc-cli merge"); return Merge::execute(argc, argv); From 64dfada038f0f72465e2c6eebcb7ce42ace340b5 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Wed, 15 Feb 2017 21:01:50 -0500 Subject: [PATCH 13/24] Adding available commands. --- src/cli/keepassxc-cli.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 67eb8e8a..c96da4d1 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -44,7 +44,15 @@ int main(int argc, char **argv) app.setApplicationVersion(KEEPASSX_VERSION); QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", "KeePassXC command line interface.")); + + QString description("KeePassXC command line interface."); + description = description.append(QString("\n\nAvailable commands:")); + description = description.append(QString("\n extract\tExtract and print a KeePassXC database file.")); + description = description.append(QString("\n entropy-meter\tCalculate password entropy.")); + description = description.append(QString("\n list\t\tList database entries.")); + description = description.append(QString("\n merge\t\tMerge 2 KeePassXC database files.")); + parser.setApplicationDescription(QCoreApplication::translate("main", qPrintable(description))); + parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute.")); parser.addHelpOption(); From f579345059815f55a88042ddb16e49a72a671b33 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Wed, 15 Feb 2017 21:05:40 -0500 Subject: [PATCH 14/24] Change cli commands description. --- src/cli/Extract.cpp | 2 +- src/cli/List.cpp | 2 +- src/cli/Merge.cpp | 2 +- src/cli/keepassxc-cli.cpp | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index b08039ae..cbdb2a39 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -36,7 +36,7 @@ int Extract::execute(int argc, char **argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", - "Extract and print a KeePassXC database file.")); + "Extract and print the content of a database.")); parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database to extract.")); parser.process(app); diff --git a/src/cli/List.cpp b/src/cli/List.cpp index 2049cc1d..0c1389d2 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -63,7 +63,7 @@ int List::execute(int argc, char **argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", - "List the passwords in the database.")); + "List database entries.")); parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database.")); parser.process(app); diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index caa8d19c..fdc81b9f 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -37,7 +37,7 @@ int Merge::execute(int argc, char** argv) QCoreApplication app(argc, argv); QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", "Merge 2 KeePassXC database files.")); + parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases.")); parser.addPositionalArgument("database1", QCoreApplication::translate("main", "path of the database to merge into.")); parser.addPositionalArgument("database2", QCoreApplication::translate("main", "path of the database to merge from.")); diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index c96da4d1..700f1263 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -47,10 +47,10 @@ int main(int argc, char **argv) QString description("KeePassXC command line interface."); description = description.append(QString("\n\nAvailable commands:")); - description = description.append(QString("\n extract\tExtract and print a KeePassXC database file.")); + description = description.append(QString("\n extract\tExtract and print the content of a database.")); description = description.append(QString("\n entropy-meter\tCalculate password entropy.")); description = description.append(QString("\n list\t\tList database entries.")); - description = description.append(QString("\n merge\t\tMerge 2 KeePassXC database files.")); + description = description.append(QString("\n merge\t\tMerge two databases.")); parser.setApplicationDescription(QCoreApplication::translate("main", qPrintable(description))); parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute.")); From 98911af39646997250bfe9c0d68b34bfe9ae4542 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Thu, 16 Feb 2017 12:53:34 -0500 Subject: [PATCH 15/24] Fixed indentation. --- src/cli/keepassxc-cli.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 700f1263..85b679bd 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -74,23 +74,23 @@ int main(int argc, char **argv) --argc; if (commandName == "list") { - argv[0] = const_cast("keepassxc-cli list"); - return List::execute(argc, argv); + argv[0] = const_cast("keepassxc-cli list"); + return List::execute(argc, argv); } if (commandName == "merge") { - argv[0] = const_cast("keepassxc-cli merge"); - return Merge::execute(argc, argv); + argv[0] = const_cast("keepassxc-cli merge"); + return Merge::execute(argc, argv); } if (commandName == "extract") { - argv[0] = const_cast("keepassxc-cli extract"); - return Extract::execute(argc, argv); + argv[0] = const_cast("keepassxc-cli extract"); + return Extract::execute(argc, argv); } if (commandName == "entropy-meter") { - argv[0] = const_cast("keepassxc-cli entropy-meter"); - return EntropyMeter::execute(argc, argv); + argv[0] = const_cast("keepassxc-cli entropy-meter"); + return EntropyMeter::execute(argc, argv); } qCritical("Invalid command %s.", qPrintable(commandName)); From e01e9715b925da073c79a92e9c882416ca84706c Mon Sep 17 00:00:00 2001 From: thez3ro Date: Thu, 16 Feb 2017 20:26:51 +0100 Subject: [PATCH 16/24] text for inserting password --- src/cli/Extract.cpp | 5 ++++- src/cli/List.cpp | 4 ++++ src/cli/Merge.cpp | 7 +++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index cbdb2a39..5bfb1185 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -33,6 +33,7 @@ int Extract::execute(int argc, char **argv) { QCoreApplication app(argc, argv); + QTextStream out(stdout); QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", @@ -46,6 +47,9 @@ int Extract::execute(int argc, char **argv) return EXIT_FAILURE; } + out << "Insert the database password\n> "; + out.flush(); + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); QString line = inputTextStream.readLine(); CompositeKey key = CompositeKey::readFromLine(line); @@ -78,7 +82,6 @@ int Extract::execute(int argc, char **argv) return EXIT_FAILURE; } - QTextStream out(stdout); out << xmlData.constData() << "\n"; return EXIT_SUCCESS; diff --git a/src/cli/List.cpp b/src/cli/List.cpp index 0c1389d2..1702a469 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -60,6 +60,7 @@ void printGroup(Group* group, QString baseName, int depth) { int List::execute(int argc, char **argv) { QCoreApplication app(argc, argv); + QTextStream out(stdout); QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", @@ -73,6 +74,9 @@ int List::execute(int argc, char **argv) return EXIT_FAILURE; } + out << "Insert the database password\n> "; + out.flush(); + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); QString line = inputTextStream.readLine(); CompositeKey key = CompositeKey::readFromLine(line); diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index fdc81b9f..0f4a9011 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -35,6 +35,7 @@ int Merge::execute(int argc, char** argv) { QCoreApplication app(argc, argv); + QTextStream out(stdout); QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases.")); @@ -53,8 +54,10 @@ int Merge::execute(int argc, char** argv) return EXIT_FAILURE; } + out << "Insert the database password\n> "; + out.flush(); + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); - QString line1 = inputTextStream.readLine(); CompositeKey key1 = CompositeKey::readFromLine(line1); @@ -128,7 +131,7 @@ int Merge::execute(int argc, char** argv) return EXIT_FAILURE; } - qDebug("Successfully merged the database files.\n"); + out << "Successfully merged the database files.\n"; return EXIT_SUCCESS; } From 15c2727a1d57980684218c60a36b1f29cf8e95a2 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 13:34:56 -0400 Subject: [PATCH 17/24] Adding the show command. --- src/cli/CMakeLists.txt | 10 +++-- src/cli/Extract.cpp | 2 +- src/cli/List.cpp | 2 +- src/cli/Merge.cpp | 6 +-- src/cli/Show.cpp | 83 +++++++++++++++++++++++++++++++++++++++ src/cli/Show.h | 27 +++++++++++++ src/cli/keepassxc-cli.cpp | 28 ++++++++----- 7 files changed, 139 insertions(+), 19 deletions(-) create mode 100644 src/cli/Show.cpp create mode 100644 src/cli/Show.h diff --git a/src/cli/CMakeLists.txt b/src/cli/CMakeLists.txt index 0ed5d991..e090ad1d 100644 --- a/src/cli/CMakeLists.txt +++ b/src/cli/CMakeLists.txt @@ -14,14 +14,16 @@ # along with this program. If not, see . set(cli_SOURCES + EntropyMeter.cpp + EntropyMeter.h + Extract.cpp + Extract.h List.cpp List.h Merge.cpp Merge.h - EntropyMeter.cpp - EntropyMeter.h - Extract.cpp - Extract.h) + Show.cpp + Show.h) add_library(cli STATIC ${cli_SOURCES}) target_link_libraries(cli Qt5::Core Qt5::Widgets) diff --git a/src/cli/Extract.cpp b/src/cli/Extract.cpp index 5bfb1185..81a9ddf0 100644 --- a/src/cli/Extract.cpp +++ b/src/cli/Extract.cpp @@ -38,7 +38,7 @@ int Extract::execute(int argc, char **argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "Extract and print the content of a database.")); - parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database to extract.")); + parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database to extract.")); parser.process(app); const QStringList args = parser.positionalArguments(); diff --git a/src/cli/List.cpp b/src/cli/List.cpp index 1702a469..cfeba3ce 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -65,7 +65,7 @@ int List::execute(int argc, char **argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "List database entries.")); - parser.addPositionalArgument("database", QCoreApplication::translate("main", "path of the database.")); + parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database.")); parser.process(app); const QStringList args = parser.positionalArguments(); diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index 0f4a9011..404892f7 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -39,11 +39,11 @@ int Merge::execute(int argc, char** argv) QCommandLineParser parser; parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases.")); - parser.addPositionalArgument("database1", QCoreApplication::translate("main", "path of the database to merge into.")); - parser.addPositionalArgument("database2", QCoreApplication::translate("main", "path of the database to merge from.")); + parser.addPositionalArgument("database1", QCoreApplication::translate("main", "Path of the database to merge into.")); + parser.addPositionalArgument("database2", QCoreApplication::translate("main", "Path of the database to merge from.")); QCommandLineOption samePasswordOption(QStringList() << "s" << "same-password", - QCoreApplication::translate("main", "use the same password for both database files.")); + QCoreApplication::translate("main", "Use the same password for both database files.")); parser.addOption(samePasswordOption); parser.process(app); diff --git a/src/cli/Show.cpp b/src/cli/Show.cpp new file mode 100644 index 00000000..c4a3b1ac --- /dev/null +++ b/src/cli/Show.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#include +#include + +#include "Show.h" + +#include +#include +#include +#include +#include + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "format/KeePass2Reader.h" +#include "keys/CompositeKey.h" + +int Show::execute(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + QTextStream out(stdout); + + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("main", + "Show a password.")); + parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database.")); + parser.addPositionalArgument("uuid", QCoreApplication::translate("main", "Uuid of the entry to show")); + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if (args.size() != 2) { + parser.showHelp(); + return EXIT_FAILURE; + } + + out << "Insert the database password\n> "; + out.flush(); + + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); + QString line = inputTextStream.readLine(); + CompositeKey key = CompositeKey::readFromLine(line); + + QString databaseFilename = args.at(0); + QFile dbFile(databaseFilename); + if (!dbFile.exists()) { + qCritical("File %s does not exist.", qPrintable(databaseFilename)); + return EXIT_FAILURE; + } + if (!dbFile.open(QIODevice::ReadOnly)) { + qCritical("Unable to open file %s.", qPrintable(databaseFilename)); + return EXIT_FAILURE; + } + + KeePass2Reader reader; + Database* db = reader.readDatabase(&dbFile, key); + + if (reader.hasError()) { + qCritical("Error while parsing the database:\n%s\n", qPrintable(reader.errorString())); + return EXIT_FAILURE; + } + + Uuid uuid = Uuid::fromHex(args.at(1)); + Entry* entry = db->resolveEntry(uuid); + out << entry->password() << "\n"; + return EXIT_SUCCESS; +} diff --git a/src/cli/Show.h b/src/cli/Show.h new file mode 100644 index 00000000..aa06b5c9 --- /dev/null +++ b/src/cli/Show.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * 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 . + */ + +#ifndef KEEPASSXC_SHOW_H +#define KEEPASSXC_SHOW_H + +class Show +{ +public: + static int execute(int argc, char** argv); +}; + +#endif // KEEPASSXC_SHOW_H diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 85b679bd..1802870e 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -21,10 +21,12 @@ #include #include +#include +#include #include #include -#include -#include +#include + #include "config-keepassx.h" #include "core/Tools.h" #include "crypto/Crypto.h" @@ -51,6 +53,7 @@ int main(int argc, char **argv) description = description.append(QString("\n entropy-meter\tCalculate password entropy.")); description = description.append(QString("\n list\t\tList database entries.")); description = description.append(QString("\n merge\t\tMerge two databases.")); + description = description.append(QString("\n show\t\tShow a password.")); parser.setApplicationDescription(QCoreApplication::translate("main", qPrintable(description))); parser.addPositionalArgument("command", QCoreApplication::translate("main", "Name of the command to execute.")); @@ -73,6 +76,16 @@ int main(int argc, char **argv) ++argv; --argc; + if (commandName == "entropy-meter") { + argv[0] = const_cast("keepassxc-cli entropy-meter"); + return EntropyMeter::execute(argc, argv); + } + + if (commandName == "extract") { + argv[0] = const_cast("keepassxc-cli extract"); + return Extract::execute(argc, argv); + } + if (commandName == "list") { argv[0] = const_cast("keepassxc-cli list"); return List::execute(argc, argv); @@ -83,14 +96,9 @@ int main(int argc, char **argv) return Merge::execute(argc, argv); } - if (commandName == "extract") { - argv[0] = const_cast("keepassxc-cli extract"); - return Extract::execute(argc, argv); - } - - if (commandName == "entropy-meter") { - argv[0] = const_cast("keepassxc-cli entropy-meter"); - return EntropyMeter::execute(argc, argv); + if (commandName == "show") { + argv[0] = const_cast("keepassxc-cli show"); + return Show::execute(argc, argv); } qCritical("Invalid command %s.", qPrintable(commandName)); From db1bf889347d3327bcd6cd0a175780746f9dcee7 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 13:37:20 -0400 Subject: [PATCH 18/24] Handling entry not found. --- src/cli/Show.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cli/Show.cpp b/src/cli/Show.cpp index c4a3b1ac..b596e521 100644 --- a/src/cli/Show.cpp +++ b/src/cli/Show.cpp @@ -78,6 +78,11 @@ int Show::execute(int argc, char **argv) Uuid uuid = Uuid::fromHex(args.at(1)); Entry* entry = db->resolveEntry(uuid); + if (entry == nullptr) { + qCritical("No entry found with uuid %s", qPrintable(uuid.toHex())); + return EXIT_FAILURE; + } + out << entry->password() << "\n"; return EXIT_SUCCESS; } From 993f90cb2cfcc71da99ea6dfef092fab9463169a Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 13:47:05 -0400 Subject: [PATCH 19/24] Extracting openDatabaseFile. --- src/cli/Show.cpp | 20 ++------------------ src/core/Database.cpp | 25 +++++++++++++++++++++++++ src/core/Database.h | 1 + 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/cli/Show.cpp b/src/cli/Show.cpp index b596e521..9222a093 100644 --- a/src/cli/Show.cpp +++ b/src/cli/Show.cpp @@ -22,14 +22,12 @@ #include #include -#include #include #include #include "core/Database.h" #include "core/Entry.h" #include "core/Group.h" -#include "format/KeePass2Reader.h" #include "keys/CompositeKey.h" int Show::execute(int argc, char **argv) @@ -57,22 +55,8 @@ int Show::execute(int argc, char **argv) QString line = inputTextStream.readLine(); CompositeKey key = CompositeKey::readFromLine(line); - QString databaseFilename = args.at(0); - QFile dbFile(databaseFilename); - if (!dbFile.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename)); - return EXIT_FAILURE; - } - if (!dbFile.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename)); - return EXIT_FAILURE; - } - - KeePass2Reader reader; - Database* db = reader.readDatabase(&dbFile, key); - - if (reader.hasError()) { - qCritical("Error while parsing the database:\n%s\n", qPrintable(reader.errorString())); + Database* db = Database::openDatabaseFile(args.at(0), key); + if (db == nullptr) { return EXIT_FAILURE; } diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 23b56414..4aa9e3f5 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -25,6 +25,7 @@ #include "core/Metadata.h" #include "crypto/Random.h" #include "format/KeePass2.h" +#include "format/KeePass2Reader.h" QHash Database::m_uuidMap; @@ -355,3 +356,27 @@ const CompositeKey & Database::key() const return m_data.key; } +Database* Database::openDatabaseFile(QString fileName, CompositeKey key) +{ + + QFile dbFile(fileName); + if (!dbFile.exists()) { + qCritical("File %s does not exist.", qPrintable(fileName)); + return nullptr; + } + if (!dbFile.open(QIODevice::ReadOnly)) { + qCritical("Unable to open file %s.", qPrintable(fileName)); + return nullptr; + } + + KeePass2Reader reader; + Database* db = reader.readDatabase(&dbFile, key); + + if (reader.hasError()) { + qCritical("Error while parsing the database: %s", qPrintable(reader.errorString())); + return nullptr; + } + + return db; + +} diff --git a/src/core/Database.h b/src/core/Database.h index 3767bb30..16c14960 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -118,6 +118,7 @@ public: Uuid uuid(); static Database* databaseByUuid(const Uuid& uuid); + static Database* openDatabaseFile(QString fileName, CompositeKey key); signals: void groupDataChanged(Group* group); From 780e23301b5bf5e27e06ac8f2397f633ce7a3424 Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 13:56:30 -0400 Subject: [PATCH 20/24] Using openDatabaseFile in Merge. --- src/cli/Merge.cpp | 43 ++++++------------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index 404892f7..118213b8 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -21,13 +21,11 @@ #include #include -#include #include #include #include #include "core/Database.h" -#include "format/KeePass2Reader.h" #include "format/KeePass2Writer.h" #include "keys/CompositeKey.h" @@ -71,50 +69,21 @@ int Merge::execute(int argc, char** argv) } - QString databaseFilename1 = args.at(0); - QFile dbFile1(databaseFilename1); - if (!dbFile1.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename1)); - return EXIT_FAILURE; - } - if (!dbFile1.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename1)); + Database* db1 = Database::openDatabaseFile(args.at(0), key1); + if (db1 == nullptr) { return EXIT_FAILURE; } - KeePass2Reader reader1; - Database* db1 = reader1.readDatabase(&dbFile1, key1); - - if (reader1.hasError()) { - qCritical("Error while parsing the database:\n%s\n", qPrintable(reader1.errorString())); - return EXIT_FAILURE; - } - - - QString databaseFilename2 = args.at(1); - QFile dbFile2(databaseFilename2); - if (!dbFile2.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename2)); - return EXIT_FAILURE; - } - if (!dbFile2.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename2)); - return EXIT_FAILURE; - } - - KeePass2Reader reader2; - Database* db2 = reader2.readDatabase(&dbFile2, key2); - - if (reader2.hasError()) { - qCritical("Error while parsing the database:\n%s\n", qPrintable(reader2.errorString())); + Database* db2 = Database::openDatabaseFile(args.at(1), key2); + if (db2 == nullptr) { return EXIT_FAILURE; } db1->merge(db2); - QSaveFile saveFile(databaseFilename1); + QSaveFile saveFile(args.at(0)); if (!saveFile.open(QIODevice::WriteOnly)) { - qCritical("Unable to open file %s for writing.", qPrintable(databaseFilename1)); + qCritical("Unable to open file %s for writing.", qPrintable(args.at(0))); return EXIT_FAILURE; } From cf2334391110d5443c37c00241bd53beee06d7db Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 13:57:44 -0400 Subject: [PATCH 21/24] Using openDatabaseFile in List. --- src/cli/List.cpp | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/cli/List.cpp b/src/cli/List.cpp index cfeba3ce..b2d673f5 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -22,14 +22,12 @@ #include #include -#include #include #include #include "core/Database.h" #include "core/Entry.h" #include "core/Group.h" -#include "format/KeePass2Reader.h" #include "keys/CompositeKey.h" void printGroup(Group* group, QString baseName, int depth) { @@ -81,22 +79,8 @@ int List::execute(int argc, char **argv) QString line = inputTextStream.readLine(); CompositeKey key = CompositeKey::readFromLine(line); - QString databaseFilename = args.at(0); - QFile dbFile(databaseFilename); - if (!dbFile.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename)); - return EXIT_FAILURE; - } - if (!dbFile.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename)); - return EXIT_FAILURE; - } - - KeePass2Reader reader; - Database* db = reader.readDatabase(&dbFile, key); - - if (reader.hasError()) { - qCritical("Error while parsing the database:\n%s\n", qPrintable(reader.errorString())); + Database* db = Database::openDatabaseFile(args.at(0), key); + if (db == nullptr) { return EXIT_FAILURE; } From fd9d372e6ab9780cb433d8ec334fcedd6550290c Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 14:17:03 -0400 Subject: [PATCH 22/24] Adding second prompt for merge. --- src/cli/Merge.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cli/Merge.cpp b/src/cli/Merge.cpp index 118213b8..aa399dd5 100644 --- a/src/cli/Merge.cpp +++ b/src/cli/Merge.cpp @@ -52,7 +52,7 @@ int Merge::execute(int argc, char** argv) return EXIT_FAILURE; } - out << "Insert the database password\n> "; + out << "Insert the first database password\n> "; out.flush(); static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); @@ -64,6 +64,8 @@ int Merge::execute(int argc, char** argv) key2 = *key1.clone(); } else { + out << "Insert the second database password\n> "; + out.flush(); QString line2 = inputTextStream.readLine(); key2 = CompositeKey::readFromLine(line2); } From a661c17eca4659303880b174ba9850b5b0c05c6e Mon Sep 17 00:00:00 2001 From: Louis-Bertrand Varin Date: Sun, 12 Mar 2017 14:24:22 -0400 Subject: [PATCH 23/24] Adding group uuid to list. --- src/cli/List.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/List.cpp b/src/cli/List.cpp index b2d673f5..1e348810 100644 --- a/src/cli/List.cpp +++ b/src/cli/List.cpp @@ -37,7 +37,7 @@ void printGroup(Group* group, QString baseName, int depth) { QString groupName = baseName + group->name() + "/"; QString indentation = QString(" ").repeated(depth); - out << indentation << groupName << "\n"; + out << indentation << groupName << " " << group->uuid().toHex() << "\n"; out.flush(); if (group->entries().isEmpty() && group->children().isEmpty()) { From 558c75a452ccafa925c658db48a9e68e875c664b Mon Sep 17 00:00:00 2001 From: thez3ro Date: Thu, 16 Mar 2017 18:41:12 +0100 Subject: [PATCH 24/24] Add ASAN to keepassxc-cli --- src/cli/keepassxc-cli.cpp | 46 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/cli/keepassxc-cli.cpp b/src/cli/keepassxc-cli.cpp index 1802870e..b27b7483 100644 --- a/src/cli/keepassxc-cli.cpp +++ b/src/cli/keepassxc-cli.cpp @@ -31,6 +31,10 @@ #include "core/Tools.h" #include "crypto/Crypto.h" +#if defined(WITH_ASAN) && defined(WITH_LSAN) +#include +#endif + int main(int argc, char **argv) { #ifdef QT_NO_DEBUG @@ -76,33 +80,35 @@ int main(int argc, char **argv) ++argv; --argc; + int exitCode = EXIT_FAILURE; + if (commandName == "entropy-meter") { argv[0] = const_cast("keepassxc-cli entropy-meter"); - return EntropyMeter::execute(argc, argv); - } - - if (commandName == "extract") { + exitCode = EntropyMeter::execute(argc, argv); + } else if (commandName == "extract") { argv[0] = const_cast("keepassxc-cli extract"); - return Extract::execute(argc, argv); - } - - if (commandName == "list") { + exitCode = Extract::execute(argc, argv); + } else if (commandName == "list") { argv[0] = const_cast("keepassxc-cli list"); - return List::execute(argc, argv); - } - - if (commandName == "merge") { + exitCode = List::execute(argc, argv); + } else if (commandName == "merge") { argv[0] = const_cast("keepassxc-cli merge"); - return Merge::execute(argc, argv); - } - - if (commandName == "show") { + exitCode = Merge::execute(argc, argv); + } else if (commandName == "show") { argv[0] = const_cast("keepassxc-cli show"); - return Show::execute(argc, argv); + exitCode = Show::execute(argc, argv); + } else { + qCritical("Invalid command %s.", qPrintable(commandName)); + parser.showHelp(); + exitCode = EXIT_FAILURE; } - qCritical("Invalid command %s.", qPrintable(commandName)); - parser.showHelp(); - return EXIT_FAILURE; +#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 + __lsan_do_leak_check(); + __lsan_disable(); +#endif + + return exitCode; }