diff --git a/.gitignore b/.gitignore index 081abf83..8882e10c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ CMakeLists.txt.* build*/ +*.swp +cmake/ diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index d0cfb5a3..3887c9a2 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -25,6 +25,16 @@ target_link_libraries(kdbx-extract ${GCRYPT_LIBRARIES} ${ZLIB_LIBRARIES}) +add_executable(merge-databases merge-databases.cpp) +target_link_libraries(merge-databases + keepassx_core + ${MHD_LIBRARIES} + Qt5::Core + Qt5::Concurrent + Qt5::Widgets + ${GCRYPT_LIBRARIES} + ${ZLIB_LIBRARIES}) + add_executable(entropy-meter entropy-meter.cpp) target_link_libraries(entropy-meter zxcvbn) diff --git a/utils/merge-databases.cpp b/utils/merge-databases.cpp new file mode 100644 index 00000000..9809aa1c --- /dev/null +++ b/utils/merge-databases.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2010 Felix Geyer + * + * 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 "core/Database.h" +#include "crypto/Crypto.h" +#include "format/KeePass2Reader.h" +#include "format/KeePass2Writer.h" +#include "keys/CompositeKey.h" +#include "keys/FileKey.h" +#include "keys/PasswordKey.h" + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + if (app.arguments().size() != 4) { + qCritical("Usage: merge-databases "); + return 1; + } + + if (!Crypto::init()) { + qFatal("Fatal error while testing the cryptographic functions:\n%s", qPrintable(Crypto::errorString())); + } + + CompositeKey key; + if (QFile::exists(app.arguments().at(1))) { + FileKey fileKey; + fileKey.load(app.arguments().at(1)); + key.addKey(fileKey); + } + else { + PasswordKey password; + password.setPassword(app.arguments().at(1)); + key.addKey(password); + } + + + QFile dbFile1(app.arguments().at(2)); + if (!dbFile1.exists()) { + qCritical("File %s does not exist.", qPrintable(app.arguments().at(2))); + return 1; + } + if (!dbFile1.open(QIODevice::ReadOnly)) { + qCritical("Unable to open file %s.", qPrintable(app.arguments().at(2))); + return 1; + } + + KeePass2Reader reader1; + Database* db1 = reader1.readDatabase(&dbFile1, key); + + if (reader1.hasError()) { + qCritical("Error while parsing the database:\n%s\n", qPrintable(reader1.errorString())); + return 1; + } + + + QFile dbFile2(app.arguments().at(3)); + if (!dbFile2.exists()) { + qCritical("File %s does not exist.", qPrintable(app.arguments().at(3))); + return 1; + } + if (!dbFile2.open(QIODevice::ReadOnly)) { + qCritical("Unable to open file %s.", qPrintable(app.arguments().at(3))); + return 1; + } + + KeePass2Reader reader2; + Database* db2 = reader2.readDatabase(&dbFile2, key); + + if (reader1.hasError()) { + qCritical("Error while parsing the database:\n%s\n", qPrintable(reader1.errorString())); + return 1; + } + + db1->merge(db2); + + QSaveFile saveFile(app.arguments().at(2)); + if (!saveFile.open(QIODevice::WriteOnly)) { + qCritical("Unable to open file %s for writing.", qPrintable(app.arguments().at(2))); + return 1; + } + + KeePass2Writer writer; + writer.writeDatabase(&saveFile, db1); + + if (writer.hasError()) { + qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString())); + return 1; + } + + if (!saveFile.commit()) { + qCritical("Error while updating the database:\n%s\n", qPrintable(writer.errorString())); + return 0; + } + + qInfo("Successfully merged the database files.\n"); + return 1; + +}