diff --git a/CMakeLists.txt b/CMakeLists.txt index e7d22312..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") @@ -254,7 +257,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/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 56% rename from utils/CMakeLists.txt rename to src/cli/CMakeLists.txt index 83f00b4b..e090ad1d 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,31 @@ # 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 + EntropyMeter.cpp + EntropyMeter.h + Extract.cpp + Extract.h + List.cpp + List.h + Merge.cpp + Merge.h + Show.cpp + Show.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}) + ${ZLIB_LIBRARIES} + zxcvbn) -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) +install(TARGETS keepassxc-cli + BUNDLE DESTINATION . COMPONENT Runtime + RUNTIME DESTINATION ${CLI_INSTALL_DIR} COMPONENT Runtime) 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/utils/kdbx-extract.cpp b/src/cli/Extract.cpp similarity index 83% rename from utils/kdbx-extract.cpp rename to src/cli/Extract.cpp index 255f5d00..81a9ddf0 100644 --- a/utils/kdbx-extract.cpp +++ b/src/cli/Extract.cpp @@ -15,8 +15,11 @@ * along with this program. If not, see . */ +#include #include +#include "Extract.h" + #include #include #include @@ -24,32 +27,28 @@ #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 main(int argc, char **argv) +int Extract::execute(int argc, char **argv) { QCoreApplication app(argc, argv); + QTextStream out(stdout); QCommandLineParser parser; 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(); + "Extract and print the content of a database.")); + parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database to extract.")); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.size() != 1) { parser.showHelp(); - return 1; + return EXIT_FAILURE; } - if (!Crypto::init()) { - qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); - } + out << "Insert the database password\n> "; + out.flush(); static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); QString line = inputTextStream.readLine(); @@ -59,11 +58,11 @@ int main(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; @@ -76,15 +75,14 @@ int main(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/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/src/cli/List.cpp b/src/cli/List.cpp new file mode 100644 index 00000000..1e348810 --- /dev/null +++ b/src/cli/List.cpp @@ -0,0 +1,89 @@ +/* + * 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 "core/Database.h" +#include "core/Entry.h" +#include "core/Group.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 << " " << group->uuid().toHex() << "\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); + QTextStream out(stdout); + + QCommandLineParser parser; + parser.setApplicationDescription(QCoreApplication::translate("main", + "List database entries.")); + 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; + } + + out << "Insert the database password\n> "; + out.flush(); + + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); + QString line = inputTextStream.readLine(); + CompositeKey key = CompositeKey::readFromLine(line); + + Database* db = Database::openDatabaseFile(args.at(0), key); + if (db == nullptr) { + 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/utils/kdbx-merge.cpp b/src/cli/Merge.cpp similarity index 55% rename from utils/kdbx-merge.cpp rename to src/cli/Merge.cpp index da780ea1..aa399dd5 100644 --- a/utils/kdbx-merge.cpp +++ b/src/cli/Merge.cpp @@ -15,50 +15,47 @@ * along with this program. If not, see . */ -#include +#include + +#include "Merge.h" #include #include -#include #include #include #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); + QTextStream out(stdout); QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::translate("main", "Merge 2 KeePassXC database files.")); - 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.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.")); 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.addHelpOption(); parser.addOption(samePasswordOption); parser.process(app); const QStringList args = parser.positionalArguments(); if (args.size() != 2) { parser.showHelp(); - return 1; - } - - if (!Crypto::init()) { - qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + return EXIT_FAILURE; } + out << "Insert the first database password\n> "; + out.flush(); + static QTextStream inputTextStream(stdin, QIODevice::ReadOnly); - QString line1 = inputTextStream.readLine(); CompositeKey key1 = CompositeKey::readFromLine(line1); @@ -67,56 +64,29 @@ int main(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); } - QString databaseFilename1 = args.at(0); - QFile dbFile1(databaseFilename1); - if (!dbFile1.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename1)); - return 1; - } - if (!dbFile1.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename1)); - return 1; + 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 1; - } - - - QString databaseFilename2 = args.at(1); - QFile dbFile2(databaseFilename2); - if (!dbFile2.exists()) { - qCritical("File %s does not exist.", qPrintable(databaseFilename2)); - return 1; - } - if (!dbFile2.open(QIODevice::ReadOnly)) { - qCritical("Unable to open file %s.", qPrintable(databaseFilename2)); - return 1; - } - - KeePass2Reader reader2; - Database* db2 = reader2.readDatabase(&dbFile2, key2); - - if (reader2.hasError()) { - qCritical("Error while parsing the database:\n%s\n", qPrintable(reader2.errorString())); - return 1; + 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)); - return 1; + qCritical("Unable to open file %s for writing.", qPrintable(args.at(0))); + return EXIT_FAILURE; } KeePass2Writer writer; @@ -124,15 +94,15 @@ int main(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 1; + out << "Successfully merged the database files.\n"; + return EXIT_SUCCESS; } 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/Show.cpp b/src/cli/Show.cpp new file mode 100644 index 00000000..9222a093 --- /dev/null +++ b/src/cli/Show.cpp @@ -0,0 +1,72 @@ +/* + * 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 "core/Database.h" +#include "core/Entry.h" +#include "core/Group.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); + + Database* db = Database::openDatabaseFile(args.at(0), key); + if (db == nullptr) { + return EXIT_FAILURE; + } + + 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; +} 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 new file mode 100644 index 00000000..b27b7483 --- /dev/null +++ b/src/cli/keepassxc-cli.cpp @@ -0,0 +1,114 @@ +/* + * 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 +#include +#include +#include + +#include "config-keepassx.h" +#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 + Tools::disableCoreDumps(); +#endif + + if (!Crypto::init()) { + qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + return EXIT_FAILURE; + } + + QCoreApplication app(argc, argv); + app.setApplicationVersion(KEEPASSX_VERSION); + + QCommandLineParser parser; + + QString description("KeePassXC command line interface."); + description = description.append(QString("\n\nAvailable commands:")); + 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 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.")); + + parser.addHelpOption(); + parser.addVersionOption(); + // 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); + + if (argc < 2) { + parser.showHelp(); + return EXIT_FAILURE; + } + + QString commandName = argv[1]; + + // Removing the first cli argument before dispatching. + ++argv; + --argc; + + int exitCode = EXIT_FAILURE; + + if (commandName == "entropy-meter") { + argv[0] = const_cast("keepassxc-cli entropy-meter"); + exitCode = EntropyMeter::execute(argc, argv); + } else if (commandName == "extract") { + argv[0] = const_cast("keepassxc-cli extract"); + exitCode = Extract::execute(argc, argv); + } else if (commandName == "list") { + argv[0] = const_cast("keepassxc-cli list"); + exitCode = List::execute(argc, argv); + } else if (commandName == "merge") { + argv[0] = const_cast("keepassxc-cli merge"); + exitCode = Merge::execute(argc, argv); + } else if (commandName == "show") { + argv[0] = const_cast("keepassxc-cli show"); + exitCode = Show::execute(argc, argv); + } else { + qCritical("Invalid command %s.", qPrintable(commandName)); + parser.showHelp(); + exitCode = 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; + +} 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);