Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJanek Bevendorff <janek@jbev.net>2017-01-15 04:20:21 +0300
committerGitHub <noreply@github.com>2017-01-15 04:20:21 +0300
commite17576a6f71c1ff3671f01be72b93ff6f7c8861a (patch)
tree941ef6d78f04890998b69803c28e083a8c174c24
parentf33cd1541941a088b90f463d457f4a9f86aa712a (diff)
parent9dadafe20a2a9c7878b4505c1aa4097c87b955f4 (diff)
Merge branch 'develop' into feature/yubikey
-rw-r--r--.github/ISSUE_TEMPLATE.md2
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md32
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/autotype/test/AutoTypeTest.cpp8
-rw-r--r--src/autotype/test/AutoTypeTest.h4
-rw-r--r--src/autotype/xcb/AutoTypeXCB.cpp16
-rw-r--r--src/autotype/xcb/AutoTypeXCB.h6
-rw-r--r--src/core/Entry.cpp6
-rw-r--r--src/core/SignalMultiplexer.cpp2
-rw-r--r--src/crypto/Crypto.cpp20
-rw-r--r--src/format/KeePass2Reader.cpp4
-rw-r--r--src/format/KeePass2Reader.h2
-rw-r--r--src/format/KeePass2XmlReader.cpp16
-rw-r--r--src/format/KeePass2XmlWriter.cpp6
-rw-r--r--src/gui/DatabaseWidget.cpp12
-rw-r--r--src/gui/entry/EditEntryWidget.cpp8
-rw-r--r--src/gui/entry/EditEntryWidgetMain.ui4
-rw-r--r--src/keys/CompositeKey.cpp28
-rw-r--r--src/keys/CompositeKey.h2
-rw-r--r--src/keys/FileKey.cpp6
-rw-r--r--src/streams/qtiocompressor.cpp12
-rw-r--r--src/zxcvbn/zxcvbn.cpp25
-rw-r--r--src/zxcvbn/zxcvbn.h2
-rw-r--r--tests/TestEntryModel.cpp14
-rw-r--r--tests/TestKeys.cpp16
-rw-r--r--tests/TestKeys.h1
-rw-r--r--tests/gui/TestGui.cpp2
-rw-r--r--utils/CMakeLists.txt10
-rw-r--r--utils/kdbx-extract.cpp34
-rw-r--r--utils/kdbx-merge.cpp138
30 files changed, 314 insertions, 126 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 5ad51c745..1a3f1a064 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -26,7 +26,7 @@
## Your Environment
<!--- Include relevant details about the environment you experienced the bug in -->
-* KeePassXR version/commit used:
+* KeePassXC version/commit used: (can be found under Help -> About)
* Qt version (e.g. Qt 5.3):
* Compiler (e.g. Clang++3.6.0):
* Operating System and version:
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 51436aada..c83ca4e53 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,4 +1,4 @@
-<!--- Provide a general summary of your changes in the Title above -->
+<!--- Provide a general summary of your changes in the title above -->
## Description
<!--- Describe your changes in detail -->
@@ -15,21 +15,19 @@
## Screenshots (if appropriate):
## Types of changes
-<!--- What types of changes does your code introduce? If it apply to your pull request, -->
-<!--- replace all the `:negative_squared_cross_mark:` with `:white_check_mark:` -->
-<!--- Everybody loves emoji -->
-- :negative_squared_cross_mark: Bug fix (non-breaking change which fixes an issue)
-- :negative_squared_cross_mark: New feature (non-breaking change which adds functionality)
-- :negative_squared_cross_mark: Breaking change (fix or feature that would cause existing functionality to change)
+<!--- What types of changes does your code introduce? -->
+<!--- Please remove all lines which don't apply. -->
+- ✅ Bug fix (non-breaking change which fixes an issue)
+- ✅ New feature (non-breaking change which adds functionality)
+- ✅ Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
-<!--- Go over all the following points, if it apply to your pull request, -->
-<!--- replace all the `:negative_squared_cross_mark:` with `:white_check_mark:`. -->
-<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
-<!--- Pull Requests that fail the [REQUIRED] field will likely be sent back for corrections or rejected -->
-- :negative_squared_cross_mark: I have read the **CONTRIBUTING** document. [REQUIRED]
-- :negative_squared_cross_mark: My code follows the code style of this project. [REQUIRED]
-- :negative_squared_cross_mark: All new and existing tests passed. [REQUIRED]
-- :negative_squared_cross_mark: My change requires a change to the documentation.
-- :negative_squared_cross_mark: I have updated the documentation accordingly.
-- :negative_squared_cross_mark: I have added tests to cover my changes.
+<!--- Please go over all the following points. -->
+<!--- Again, remove any lines which don't apply. -->
+<!--- Pull Requests that don't fulfill all [REQUIRED] requisites are likely -->
+<!--- to be sent back to you for correction or will be rejected. -->
+- ✅ I have read the **CONTRIBUTING** document. **[REQUIRED]**
+- ✅ My code follows the code style of this project. **[REQUIRED]**
+- ✅ All new and existing tests passed. **[REQUIRED]**
+- ✅ My change requires a change to the documentation and I have updated it accordingly.
+- ✅ I have added tests to cover my changes.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ff7b05e5a..0843d7ccb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,7 +15,7 @@
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
- "Choose the type of build, options are: None Debug Release RelWithDebInfo Debug Debugfull Profile MinSizeRel."
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo Debug DebugFull Profile MinSizeRel."
FORCE)
endif()
diff --git a/src/autotype/test/AutoTypeTest.cpp b/src/autotype/test/AutoTypeTest.cpp
index 1ac815b0e..0eaf71602 100644
--- a/src/autotype/test/AutoTypeTest.cpp
+++ b/src/autotype/test/AutoTypeTest.cpp
@@ -65,7 +65,7 @@ int AutoTypePlatformTest::platformEventFilter(void* event)
AutoTypeExecutor* AutoTypePlatformTest::createExecutor()
{
- return new AutoTypeExecturorTest(this);
+ return new AutoTypeExecutorTest(this);
}
void AutoTypePlatformTest::setActiveWindowTitle(const QString& title)
@@ -127,17 +127,17 @@ bool AutoTypePlatformTest::raiseOwnWindow()
}
#endif
-AutoTypeExecturorTest::AutoTypeExecturorTest(AutoTypePlatformTest* platform)
+AutoTypeExecutorTest::AutoTypeExecutorTest(AutoTypePlatformTest* platform)
: m_platform(platform)
{
}
-void AutoTypeExecturorTest::execChar(AutoTypeChar* action)
+void AutoTypeExecutorTest::execChar(AutoTypeChar* action)
{
m_platform->addActionChar(action);
}
-void AutoTypeExecturorTest::execKey(AutoTypeKey* action)
+void AutoTypeExecutorTest::execKey(AutoTypeKey* action)
{
m_platform->addActionKey(action);
}
diff --git a/src/autotype/test/AutoTypeTest.h b/src/autotype/test/AutoTypeTest.h
index 33487778a..4feaab942 100644
--- a/src/autotype/test/AutoTypeTest.h
+++ b/src/autotype/test/AutoTypeTest.h
@@ -69,10 +69,10 @@ private:
QString m_actionChars;
};
-class AutoTypeExecturorTest : public AutoTypeExecutor
+class AutoTypeExecutorTest : public AutoTypeExecutor
{
public:
- explicit AutoTypeExecturorTest(AutoTypePlatformTest* platform);
+ explicit AutoTypeExecutorTest(AutoTypePlatformTest* platform);
void execChar(AutoTypeChar* action) override;
void execKey(AutoTypeKey* action) override;
diff --git a/src/autotype/xcb/AutoTypeXCB.cpp b/src/autotype/xcb/AutoTypeXCB.cpp
index 23a211d37..f419875dc 100644
--- a/src/autotype/xcb/AutoTypeXCB.cpp
+++ b/src/autotype/xcb/AutoTypeXCB.cpp
@@ -24,7 +24,7 @@
#include <xcb/xcb.h>
bool AutoTypePlatformX11::m_catchXErrors = false;
-bool AutoTypePlatformX11::m_xErrorOccured = false;
+bool AutoTypePlatformX11::m_xErrorOccurred = false;
int (*AutoTypePlatformX11::m_oldXErrorHandler)(Display*, XErrorEvent*) = nullptr;
AutoTypePlatformX11::AutoTypePlatformX11()
@@ -153,7 +153,7 @@ bool AutoTypePlatformX11::registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifi
GrabModeAsync, GrabModeAsync);
stopCatchXErrors();
- if (!m_xErrorOccured) {
+ if (!m_xErrorOccurred) {
m_currentGlobalKey = key;
m_currentGlobalModifiers = modifiers;
m_currentGlobalKeycode = keycode;
@@ -247,7 +247,7 @@ int AutoTypePlatformX11::platformEventFilter(void* event)
AutoTypeExecutor* AutoTypePlatformX11::createExecutor()
{
- return new AutoTypeExecturorX11(this);
+ return new AutoTypeExecutorX11(this);
}
QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist)
@@ -556,7 +556,7 @@ void AutoTypePlatformX11::startCatchXErrors()
Q_ASSERT(!m_catchXErrors);
m_catchXErrors = true;
- m_xErrorOccured = false;
+ m_xErrorOccurred = false;
m_oldXErrorHandler = XSetErrorHandler(x11ErrorHandler);
}
@@ -575,7 +575,7 @@ int AutoTypePlatformX11::x11ErrorHandler(Display* display, XErrorEvent* error)
Q_UNUSED(error)
if (m_catchXErrors) {
- m_xErrorOccured = true;
+ m_xErrorOccurred = true;
}
return 1;
@@ -823,17 +823,17 @@ int AutoTypePlatformX11::MyErrorHandler(Display* my_dpy, XErrorEvent* event)
}
-AutoTypeExecturorX11::AutoTypeExecturorX11(AutoTypePlatformX11* platform)
+AutoTypeExecutorX11::AutoTypeExecutorX11(AutoTypePlatformX11* platform)
: m_platform(platform)
{
}
-void AutoTypeExecturorX11::execChar(AutoTypeChar* action)
+void AutoTypeExecutorX11::execChar(AutoTypeChar* action)
{
m_platform->SendKeyPressedEvent(m_platform->charToKeySym(action->character));
}
-void AutoTypeExecturorX11::execKey(AutoTypeKey* action)
+void AutoTypeExecutorX11::execKey(AutoTypeKey* action)
{
m_platform->SendKeyPressedEvent(m_platform->keyToKeySym(action->key));
}
diff --git a/src/autotype/xcb/AutoTypeXCB.h b/src/autotype/xcb/AutoTypeXCB.h
index 8adee7701..26d1e8102 100644
--- a/src/autotype/xcb/AutoTypeXCB.h
+++ b/src/autotype/xcb/AutoTypeXCB.h
@@ -100,7 +100,7 @@ private:
uint m_currentGlobalNativeModifiers;
int m_modifierMask;
static bool m_catchXErrors;
- static bool m_xErrorOccured;
+ static bool m_xErrorOccurred;
static int (*m_oldXErrorHandler)(Display*, XErrorEvent*);
static const int m_unicodeToKeysymLen;
@@ -119,10 +119,10 @@ private:
bool m_loaded;
};
-class AutoTypeExecturorX11 : public AutoTypeExecutor
+class AutoTypeExecutorX11 : public AutoTypeExecutor
{
public:
- explicit AutoTypeExecturorX11(AutoTypePlatformX11* platform);
+ explicit AutoTypeExecutorX11(AutoTypePlatformX11* platform);
void execChar(AutoTypeChar* action) override;
void execKey(AutoTypeKey* action) override;
diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp
index 629f5141c..b2b06e7c8 100644
--- a/src/core/Entry.cpp
+++ b/src/core/Entry.cpp
@@ -449,7 +449,7 @@ void Entry::truncateHistory()
int histMaxSize = db->metadata()->historyMaxSize();
if (histMaxSize > -1) {
int size = 0;
- QSet<QByteArray> foundAttachements = attachments()->values().toSet();
+ QSet<QByteArray> foundAttachments = attachments()->values().toSet();
QMutableListIterator<Entry*> i(m_history);
i.toBack();
@@ -460,11 +460,11 @@ void Entry::truncateHistory()
if (size <= histMaxSize) {
size += historyItem->attributes()->attributesSize();
- const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachements;
+ const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachments;
for (const QByteArray& attachment : newAttachments) {
size += attachment.size();
}
- foundAttachements += newAttachments;
+ foundAttachments += newAttachments;
}
if (size > histMaxSize) {
diff --git a/src/core/SignalMultiplexer.cpp b/src/core/SignalMultiplexer.cpp
index 7b5fab93b..0f99b8e65 100644
--- a/src/core/SignalMultiplexer.cpp
+++ b/src/core/SignalMultiplexer.cpp
@@ -36,7 +36,7 @@ QObject* SignalMultiplexer::currentObject() const
void SignalMultiplexer::setCurrentObject(QObject* object)
{
- // remove all Connections from the list whoes senders/receivers have been deleted
+ // remove all Connections from the list whose senders/receivers have been deleted
QMutableListIterator<Connection> i = m_connections;
while (i.hasNext()) {
const Connection& con = i.next();
diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp
index 4669de69a..d00be720b 100644
--- a/src/crypto/Crypto.cpp
+++ b/src/crypto/Crypto.cpp
@@ -153,14 +153,14 @@ bool Crypto::testAes256Cbc()
return false;
}
- SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
- if (!aes256Descrypt.init(key, iv)) {
- raiseError(aes256Descrypt.errorString());
+ SymmetricCipher aes256Decrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
+ if (!aes256Decrypt.init(key, iv)) {
+ raiseError(aes256Decrypt.errorString());
return false;
}
- QByteArray decryptedText = aes256Descrypt.process(cipherText, &ok);
+ QByteArray decryptedText = aes256Decrypt.process(cipherText, &ok);
if (!ok) {
- raiseError(aes256Descrypt.errorString());
+ raiseError(aes256Decrypt.errorString());
return false;
}
if (decryptedText != plainText) {
@@ -196,14 +196,14 @@ bool Crypto::testAes256Ecb()
return false;
}
- SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Ecb, SymmetricCipher::Decrypt);
- if (!aes256Descrypt.init(key, iv)) {
- raiseError(aes256Descrypt.errorString());
+ SymmetricCipher aes256Decrypt(SymmetricCipher::Aes256, SymmetricCipher::Ecb, SymmetricCipher::Decrypt);
+ if (!aes256Decrypt.init(key, iv)) {
+ raiseError(aes256Decrypt.errorString());
return false;
}
- QByteArray decryptedText = aes256Descrypt.process(cipherText, &ok);
+ QByteArray decryptedText = aes256Decrypt.process(cipherText, &ok);
if (!ok) {
- raiseError(aes256Descrypt.errorString());
+ raiseError(aes256Decrypt.errorString());
return false;
}
if (decryptedText != plainText) {
diff --git a/src/format/KeePass2Reader.cpp b/src/format/KeePass2Reader.cpp
index 73960a7a1..0512be601 100644
--- a/src/format/KeePass2Reader.cpp
+++ b/src/format/KeePass2Reader.cpp
@@ -301,7 +301,7 @@ bool KeePass2Reader::readHeaderField()
break;
case KeePass2::TransformRounds:
- setTansformRounds(fieldData);
+ setTransformRounds(fieldData);
break;
case KeePass2::EncryptionIV:
@@ -382,7 +382,7 @@ void KeePass2Reader::setTransformSeed(const QByteArray& data)
}
}
-void KeePass2Reader::setTansformRounds(const QByteArray& data)
+void KeePass2Reader::setTransformRounds(const QByteArray& data)
{
if (data.size() != 8) {
raiseError("Invalid transform rounds size");
diff --git a/src/format/KeePass2Reader.h b/src/format/KeePass2Reader.h
index 827e671cd..f8b962535 100644
--- a/src/format/KeePass2Reader.h
+++ b/src/format/KeePass2Reader.h
@@ -48,7 +48,7 @@ private:
void setCompressionFlags(const QByteArray& data);
void setMasterSeed(const QByteArray& data);
void setTransformSeed(const QByteArray& data);
- void setTansformRounds(const QByteArray& data);
+ void setTransformRounds(const QByteArray& data);
void setEncryptionIV(const QByteArray& data);
void setProtectedStreamKey(const QByteArray& data);
void setStreamStartBytes(const QByteArray& data);
diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp
index f70672592..dfb03bd06 100644
--- a/src/format/KeePass2XmlReader.cpp
+++ b/src/format/KeePass2XmlReader.cpp
@@ -178,7 +178,7 @@ bool KeePass2XmlReader::parseKeePassFile()
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile");
bool rootElementFound = false;
- bool rootParsedSuccesfully = false;
+ bool rootParsedSuccessfully = false;
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Meta") {
@@ -186,11 +186,11 @@ bool KeePass2XmlReader::parseKeePassFile()
}
else if (m_xml.name() == "Root") {
if (rootElementFound) {
- rootParsedSuccesfully = false;
+ rootParsedSuccessfully = false;
raiseError("Multiple root elements");
}
else {
- rootParsedSuccesfully = parseRoot();
+ rootParsedSuccessfully = parseRoot();
rootElementFound = true;
}
}
@@ -199,7 +199,7 @@ bool KeePass2XmlReader::parseKeePassFile()
}
}
- return rootParsedSuccesfully;
+ return rootParsedSuccessfully;
}
void KeePass2XmlReader::parseMeta()
@@ -458,12 +458,12 @@ bool KeePass2XmlReader::parseRoot()
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root");
bool groupElementFound = false;
- bool groupParsedSuccesfully = false;
+ bool groupParsedSuccessfully = false;
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Group") {
if (groupElementFound) {
- groupParsedSuccesfully = false;
+ groupParsedSuccessfully = false;
raiseError("Multiple group elements");
continue;
}
@@ -473,7 +473,7 @@ bool KeePass2XmlReader::parseRoot()
Group* oldRoot = m_db->rootGroup();
m_db->setRootGroup(rootGroup);
delete oldRoot;
- groupParsedSuccesfully = true;
+ groupParsedSuccessfully = true;
}
groupElementFound = true;
@@ -486,7 +486,7 @@ bool KeePass2XmlReader::parseRoot()
}
}
- return groupParsedSuccesfully;
+ return groupParsedSuccessfully;
}
Group* KeePass2XmlReader::parseGroup()
diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp
index 6c92c4b39..f8dfa1581 100644
--- a/src/format/KeePass2XmlWriter.cpp
+++ b/src/format/KeePass2XmlWriter.cpp
@@ -566,9 +566,9 @@ QString KeePass2XmlWriter::stripInvalidXml10Chars(QString str)
// keep valid surrogate pair
i--;
}
- else if ((uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D) // control chracters
- || (uc >= 0x7F && uc <= 0x84) // control chracters, valid but discouraged by XML
- || (uc >= 0x86 && uc <= 0x9F) // control chracters, valid but discouraged by XML
+ else if ((uc < 0x20 && uc != 0x09 && uc != 0x0A && uc != 0x0D) // control characters
+ || (uc >= 0x7F && uc <= 0x84) // control characters, valid but discouraged by XML
+ || (uc >= 0x86 && uc <= 0x9F) // control characters, valid but discouraged by XML
|| (uc > 0xFFFD) // noncharacter
|| ch.isLowSurrogate() // single low surrogate
|| ch.isHighSurrogate()) // single high surrogate
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp
index 263bc43fa..985374c49 100644
--- a/src/gui/DatabaseWidget.cpp
+++ b/src/gui/DatabaseWidget.cpp
@@ -333,8 +333,8 @@ void DatabaseWidget::deleteEntries()
selectedEntries.append(m_entryView->entryFromIndex(index));
}
- bool inRecylceBin = Tools::hasChild(m_db->metadata()->recycleBin(), selectedEntries.first());
- if (inRecylceBin || !m_db->metadata()->recycleBinEnabled()) {
+ bool inRecycleBin = Tools::hasChild(m_db->metadata()->recycleBin(), selectedEntries.first());
+ if (inRecycleBin || !m_db->metadata()->recycleBinEnabled()) {
QMessageBox::StandardButton result;
if (selected.size() == 1) {
@@ -525,10 +525,10 @@ void DatabaseWidget::deleteGroup()
return;
}
- bool inRecylceBin = Tools::hasChild(m_db->metadata()->recycleBin(), currentGroup);
+ bool inRecycleBin = Tools::hasChild(m_db->metadata()->recycleBin(), currentGroup);
bool isRecycleBin = (currentGroup == m_db->metadata()->recycleBin());
bool isRecycleBinSubgroup = Tools::hasChild(currentGroup, m_db->metadata()->recycleBin());
- if (inRecylceBin || isRecycleBin || isRecycleBinSubgroup || !m_db->metadata()->recycleBinEnabled()) {
+ if (inRecycleBin || isRecycleBin || isRecycleBinSubgroup || !m_db->metadata()->recycleBinEnabled()) {
QMessageBox::StandardButton result = MessageBox::question(
this, tr("Delete group?"),
tr("Do you really want to delete the group \"%1\" for good?")
@@ -1033,13 +1033,13 @@ void DatabaseWidget::reloadDatabaseFile()
else {
MessageBox::critical(this, tr("Autoreload Failed"),
tr("Could not parse or unlock the new database file while attempting"
- "to autoreload this database."));
+ " to autoreload this database."));
}
}
else {
MessageBox::critical(this, tr("Autoreload Failed"),
tr("Could not open the new database file while attempting to autoreload"
- "this database."));
+ " this database."));
}
// Rewatch the database file
diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp
index 344a329fa..d9ba5bd83 100644
--- a/src/gui/entry/EditEntryWidget.cpp
+++ b/src/gui/entry/EditEntryWidget.cpp
@@ -90,7 +90,7 @@ void EditEntryWidget::setupMain()
m_mainUi->togglePasswordButton->setIcon(filePath()->onOffIcon("actions", "password-show"));
connect(m_mainUi->togglePasswordButton, SIGNAL(toggled(bool)), m_mainUi->passwordEdit, SLOT(setShowPassword(bool)));
- connect(m_mainUi->tooglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
+ connect(m_mainUi->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
connect(m_mainUi->expireCheck, SIGNAL(toggled(bool)), m_mainUi->expireDatePicker, SLOT(setEnabled(bool)));
m_mainUi->passwordRepeatEdit->enableVerifyMode(m_mainUi->passwordEdit);
connect(m_mainUi->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString)));
@@ -299,8 +299,8 @@ void EditEntryWidget::setForms(const Entry* entry, bool restore)
m_mainUi->expireCheck->setEnabled(!m_history);
m_mainUi->expireDatePicker->setReadOnly(m_history);
m_mainUi->notesEdit->setReadOnly(m_history);
- m_mainUi->tooglePasswordGeneratorButton->setChecked(false);
- m_mainUi->tooglePasswordGeneratorButton->setDisabled(m_history);
+ m_mainUi->togglePasswordGeneratorButton->setChecked(false);
+ m_mainUi->togglePasswordGeneratorButton->setDisabled(m_history);
m_mainUi->passwordGenerator->reset();
m_advancedUi->addAttachmentButton->setEnabled(!m_history);
updateAttachmentButtonsEnabled(m_advancedUi->attachmentsView->currentIndex());
@@ -529,7 +529,7 @@ void EditEntryWidget::setGeneratedPassword(const QString& password)
m_mainUi->passwordEdit->setText(password);
m_mainUi->passwordRepeatEdit->setText(password);
- m_mainUi->tooglePasswordGeneratorButton->setChecked(false);
+ m_mainUi->togglePasswordGeneratorButton->setChecked(false);
}
void EditEntryWidget::insertAttribute()
diff --git a/src/gui/entry/EditEntryWidgetMain.ui b/src/gui/entry/EditEntryWidgetMain.ui
index ebf32425f..083f1c033 100644
--- a/src/gui/entry/EditEntryWidgetMain.ui
+++ b/src/gui/entry/EditEntryWidgetMain.ui
@@ -76,7 +76,7 @@
</widget>
</item>
<item>
- <widget class="QToolButton" name="tooglePasswordGeneratorButton">
+ <widget class="QToolButton" name="togglePasswordGeneratorButton">
<property name="text">
<string>Generate</string>
</property>
@@ -166,7 +166,7 @@
<tabstop>passwordEdit</tabstop>
<tabstop>passwordRepeatEdit</tabstop>
<tabstop>togglePasswordButton</tabstop>
- <tabstop>tooglePasswordGeneratorButton</tabstop>
+ <tabstop>togglePasswordGeneratorButton</tabstop>
<tabstop>urlEdit</tabstop>
<tabstop>expireCheck</tabstop>
<tabstop>expireDatePicker</tabstop>
diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp
index ae654eb74..4e79cd05c 100644
--- a/src/keys/CompositeKey.cpp
+++ b/src/keys/CompositeKey.cpp
@@ -19,12 +19,15 @@
#include "CompositeKey_p.h"
#include "ChallengeResponseKey.h"
-#include <QtConcurrent>
#include <QElapsedTimer>
+#include <QFile>
+#include <QtConcurrent>
#include "core/Global.h"
#include "crypto/CryptoHash.h"
#include "crypto/SymmetricCipher.h"
+#include "keys/FileKey.h"
+#include "keys/PasswordKey.h"
CompositeKey::CompositeKey()
{
@@ -77,6 +80,29 @@ 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 b5f973d20..531c2d9b2 100644
--- a/src/keys/CompositeKey.h
+++ b/src/keys/CompositeKey.h
@@ -19,6 +19,7 @@
#define KEEPASSX_COMPOSITEKEY_H
#include <QList>
+#include <QString>
#include "keys/Key.h"
#include "keys/ChallengeResponseKey.h"
@@ -43,6 +44,7 @@ public:
void addChallengeResponseKey(const ChallengeResponseKey& key);
static int transformKeyBenchmark(int msec);
+ static CompositeKey readFromLine(QString line);
private:
static QByteArray transformKeyRaw(const QByteArray& key, const QByteArray& seed,
diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp
index d399f545f..d3cdfe040 100644
--- a/src/keys/FileKey.cpp
+++ b/src/keys/FileKey.cpp
@@ -190,18 +190,18 @@ bool FileKey::loadXml(QIODevice* device)
bool FileKey::loadXmlMeta(QXmlStreamReader& xmlReader)
{
- bool corectVersion = false;
+ bool correctVersion = false;
while (!xmlReader.error() && xmlReader.readNextStartElement()) {
if (xmlReader.name() == "Version") {
// TODO: error message about incompatible key file version
if (xmlReader.readElementText() == "1.00") {
- corectVersion = true;
+ correctVersion = true;
}
}
}
- return corectVersion;
+ return correctVersion;
}
QByteArray FileKey::loadXmlKey(QXmlStreamReader& xmlReader)
diff --git a/src/streams/qtiocompressor.cpp b/src/streams/qtiocompressor.cpp
index be6ac5dfd..97955e472 100644
--- a/src/streams/qtiocompressor.cpp
+++ b/src/streams/qtiocompressor.cpp
@@ -135,7 +135,7 @@ void QtIOCompressorPrivate::flushZlib(int flushMode)
if (!writeBytes(buffer, outputSize))
return;
- // If the mode is Z_FNISH we must loop until we get Z_STREAM_END,
+ // If the mode is Z_FINISH we must loop until we get Z_STREAM_END,
// else we loop as long as zlib is able to fill the output buffer.
} while ((flushMode == Z_FINISH && status != Z_STREAM_END) || (flushMode != Z_FINISH && zlibStream.avail_out == 0));
@@ -522,11 +522,11 @@ qint64 QtIOCompressor::readData(char *data, qint64 maxSize)
// Read data if if the input buffer is empty. There could be data in the buffer
// from a previous readData call.
if (d->zlibStream.avail_in == 0) {
- qint64 bytesAvalible = d->device->read(reinterpret_cast<char *>(d->buffer), d->bufferSize);
+ qint64 bytesAvailable = d->device->read(reinterpret_cast<char *>(d->buffer), d->bufferSize);
d->zlibStream.next_in = d->buffer;
- d->zlibStream.avail_in = bytesAvalible;
+ d->zlibStream.avail_in = bytesAvailable;
- if (bytesAvalible == -1) {
+ if (bytesAvailable == -1) {
d->state = QtIOCompressorPrivate::Error;
setErrorString(QT_TRANSLATE_NOOP("QtIOCompressor", "Error reading data from underlying device: ") + d->device->errorString());
return -1;
@@ -534,9 +534,9 @@ qint64 QtIOCompressor::readData(char *data, qint64 maxSize)
if (d->state != QtIOCompressorPrivate::InStream) {
// If we are not in a stream and get 0 bytes, we are probably trying to read from an empty device.
- if(bytesAvalible == 0)
+ if(bytesAvailable == 0)
return 0;
- else if (bytesAvalible > 0)
+ else if (bytesAvailable > 0)
d->state = QtIOCompressorPrivate::InStream;
}
}
diff --git a/src/zxcvbn/zxcvbn.cpp b/src/zxcvbn/zxcvbn.cpp
index 5e5678332..25cbe5440 100644
--- a/src/zxcvbn/zxcvbn.cpp
+++ b/src/zxcvbn/zxcvbn.cpp
@@ -1,4 +1,4 @@
-/**********************************************************************************
+/**********************************************************************************
* C implementation of the zxcvbn password strength estimation method.
* Copyright (c) 2015, Tony Evans
* All rights reserved.
@@ -228,12 +228,13 @@ static void AddMatchRepeats(ZxcMatch_t **Result, ZxcMatch_t *Match, const uint8_
while(MaxLen >= (Len * RepeatCount))
{
- if (strncmp((const char *)Passwd, (const char *)Rpt, Len) == 0)
+ if (strncmp(reinterpret_cast<const char *>(Passwd),
+ reinterpret_cast<const char *>(Rpt), Len) == 0)
{
/* Found a repeat */
ZxcMatch_t *p = AllocMatch();
p->Entrpy = Match->Entrpy + log(RepeatCount);
- p->Type = (ZxcTypeMatch_t)(Match->Type + MULTIPLE_MATCH);
+ p->Type = static_cast<ZxcTypeMatch_t>(Match->Type + MULTIPLE_MATCH);
p->Length = Len * RepeatCount;
p->Begin = Match->Begin;
AddResult(Result, p, MaxLen);
@@ -617,7 +618,7 @@ static void DictionaryEntropy(ZxcMatch_t *m, DictMatchInfo_t *Extra, const uint8
e += d;
}
/* Add entropy due to word's rank */
- e += log((double)Extra->Rank);
+ e += log(static_cast<double>(Extra->Rank));
m->Entrpy = e;
}
@@ -794,7 +795,7 @@ static void UserMatch(ZxcMatch_t **Result, const char *Words[], const uint8_t *P
int Caps = 0;
int Lowers = 0;
int Leets = 0;
- const uint8_t *Wrd = (const uint8_t *)(Words[Rank]);
+ const uint8_t *Wrd = reinterpret_cast<const uint8_t *>(Words[Rank]);
const uint8_t *Pwd = Passwd;
memset(Extra.Leeted, 0, sizeof Extra.Leeted);
memset(Extra.UnLeet, 0, sizeof Extra.UnLeet);
@@ -1169,7 +1170,7 @@ static void SpatialMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start,
int i, j, s;
double Degree, Entropy;
ZxcMatch_t *p;
- Degree = (k->NumNear-1) - (double)k->NumBlank / (double)k->NumKeys;
+ Degree = (k->NumNear-1) - static_cast<double>(k->NumBlank) / static_cast<double>(k->NumKeys);
s = k->NumKeys;
if (k->Shifts)
s *= 2;
@@ -1405,13 +1406,13 @@ static void RepeatMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start, i
int RepeatCount = 2;
while(MaxLen >= (Len * RepeatCount))
{
- if (strncmp((const char *)Passwd, (const char *)Rpt, Len) == 0)
+ if (strncmp(reinterpret_cast<const char *>(Passwd), reinterpret_cast<const char *>(Rpt), Len) == 0)
{
/* Found a repeat */
int c = Cardinality(Passwd, Len);
ZxcMatch_t *p = AllocMatch();
- p->Entrpy = log((double)c) * Len + log(RepeatCount);
- p->Type = (ZxcTypeMatch_t)(BRUTE_MATCH + MULTIPLE_MATCH);
+ p->Entrpy = log(static_cast<double>(c)) * Len + log(RepeatCount);
+ p->Type = static_cast<ZxcTypeMatch_t>(BRUTE_MATCH + MULTIPLE_MATCH);
p->Length = Len * RepeatCount;
p->Begin = Start;
AddResult(Result, p, MaxLen);
@@ -1527,7 +1528,7 @@ static void SequenceMatch(ZxcMatch_t **Result, const uint8_t *Passwd, int Start,
p->Type = SEQUENCE_MATCH;
p->Begin = Start;
p->Length = i;
- p->Entrpy = e + log((double)i);
+ p->Entrpy = e + log(static_cast<double>(i));
AddMatchRepeats(Result, p, Pwd, MaxLen);
AddResult(Result, p, MaxLen);
}
@@ -1578,13 +1579,13 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
Node_t *Np;
double e;
int Len = strlen(Pwd);
- const uint8_t *Passwd = (const uint8_t *)Pwd;
+ const uint8_t *Passwd = reinterpret_cast<const uint8_t *>(Pwd);
uint8_t *RevPwd;
/* Create the paths */
Node_t *Nodes = MallocFn(Node_t, Len+1);
memset(Nodes, 0, (Len+1) * sizeof *Nodes);
i = Cardinality(Passwd, Len);
- e = log((double)i);
+ e = log(static_cast<double>(i));
/* Do matching for all parts of the password */
for(i = 0; i < Len; ++i)
diff --git a/src/zxcvbn/zxcvbn.h b/src/zxcvbn/zxcvbn.h
index 796d6b47b..2d3ec52c1 100644
--- a/src/zxcvbn/zxcvbn.h
+++ b/src/zxcvbn/zxcvbn.h
@@ -1,4 +1,4 @@
-#ifndef ZXCVBN_H_F98183CE2A01_INCLUDED
+#ifndef ZXCVBN_H_F98183CE2A01_INCLUDED
#define ZXCVBN_H_F98183CE2A01_INCLUDED
/**********************************************************************************
* C implementation of the zxcvbn password strength estimation method.
diff --git a/tests/TestEntryModel.cpp b/tests/TestEntryModel.cpp
index 3f956d7f3..d5a16ebab 100644
--- a/tests/TestEntryModel.cpp
+++ b/tests/TestEntryModel.cpp
@@ -236,15 +236,15 @@ void TestEntryModel::testAutoTypeAssociationsModel()
QCOMPARE(model->rowCount(), 0);
- AutoTypeAssociations* assocications = new AutoTypeAssociations(this);
- model->setAutoTypeAssociations(assocications);
+ AutoTypeAssociations* associations = new AutoTypeAssociations(this);
+ model->setAutoTypeAssociations(associations);
QCOMPARE(model->rowCount(), 0);
AutoTypeAssociations::Association assoc;
assoc.window = "1";
assoc.sequence = "2";
- assocications->add(assoc);
+ associations->add(assoc);
QCOMPARE(model->rowCount(), 1);
QCOMPARE(model->data(model->index(0, 0)).toString(), QString("1"));
@@ -252,17 +252,17 @@ void TestEntryModel::testAutoTypeAssociationsModel()
assoc.window = "3";
assoc.sequence = "4";
- assocications->update(0, assoc);
+ associations->update(0, assoc);
QCOMPARE(model->data(model->index(0, 0)).toString(), QString("3"));
QCOMPARE(model->data(model->index(0, 1)).toString(), QString("4"));
- assocications->add(assoc);
- assocications->remove(0);
+ associations->add(assoc);
+ associations->remove(0);
QCOMPARE(model->rowCount(), 1);
delete modelTest;
delete model;
- delete assocications;
+ delete associations;
}
void TestEntryModel::testProxyModel()
diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp
index 6c1953faf..d5b35b1fb 100644
--- a/tests/TestKeys.cpp
+++ b/tests/TestKeys.cpp
@@ -83,6 +83,22 @@ 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 0f14117fd..a6d0b7e1a 100644
--- a/tests/TestKeys.h
+++ b/tests/TestKeys.h
@@ -27,6 +27,7 @@ class TestKeys : public QObject
private Q_SLOTS:
void initTestCase();
void testComposite();
+ void testCompositeKeyReadFromLine();
void testFileKey();
void testFileKey_data();
void testCreateFileKey();
diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp
index 01f165243..babab8ab7 100644
--- a/tests/gui/TestGui.cpp
+++ b/tests/gui/TestGui.cpp
@@ -328,7 +328,7 @@ void TestGui::testEntryEntropy()
QTest::keyClicks(titleEdit, "test");
// Open the password generator
- QToolButton* generatorButton = editEntryWidget->findChild<QToolButton*>("tooglePasswordGeneratorButton");
+ QToolButton* generatorButton = editEntryWidget->findChild<QToolButton*>("togglePasswordGeneratorButton");
QTest::mouseClick(generatorButton, Qt::LeftButton);
// Type in some password
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index d0cfb5a31..846e39230 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -18,10 +18,14 @@ include_directories(../src)
add_executable(kdbx-extract kdbx-extract.cpp)
target_link_libraries(kdbx-extract
keepassx_core
- ${MHD_LIBRARIES}
Qt5::Core
- Qt5::Concurrent
- Qt5::Widgets
+ ${GCRYPT_LIBRARIES}
+ ${ZLIB_LIBRARIES})
+
+add_executable(kdbx-merge kdbx-merge.cpp)
+target_link_libraries(kdbx-merge
+ keepassx_core
+ Qt5::Core
${GCRYPT_LIBRARIES}
${ZLIB_LIBRARIES})
diff --git a/utils/kdbx-extract.cpp b/utils/kdbx-extract.cpp
index f5d2a19a6..255f5d003 100644
--- a/utils/kdbx-extract.cpp
+++ b/utils/kdbx-extract.cpp
@@ -17,6 +17,7 @@
#include <stdio.h>
+#include <QCommandLineParser>
#include <QCoreApplication>
#include <QFile>
#include <QStringList>
@@ -33,8 +34,16 @@ int main(int argc, char **argv)
{
QCoreApplication app(argc, argv);
- if (app.arguments().size() != 3) {
- qCritical("Usage: kdbx-extract <password/key file> <kdbx file>");
+ 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();
+ parser.process(app);
+
+ const QStringList args = parser.positionalArguments();
+ if (args.size() != 1) {
+ parser.showHelp();
return 1;
}
@@ -42,25 +51,18 @@ int main(int argc, char **argv)
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);
- }
+ static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
+ QString line = inputTextStream.readLine();
+ CompositeKey key = CompositeKey::readFromLine(line);
- QFile dbFile(app.arguments().at(2));
+ QString databaseFilename = args.at(0);
+ QFile dbFile(databaseFilename);
if (!dbFile.exists()) {
- qCritical("File does not exist.");
+ qCritical("File %s does not exist.", qPrintable(databaseFilename));
return 1;
}
if (!dbFile.open(QIODevice::ReadOnly)) {
- qCritical("Unable to open file.");
+ qCritical("Unable to open file %s.", qPrintable(databaseFilename));
return 1;
}
diff --git a/utils/kdbx-merge.cpp b/utils/kdbx-merge.cpp
new file mode 100644
index 000000000..da780ea1b
--- /dev/null
+++ b/utils/kdbx-merge.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 or (at your option)
+ * version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include <QCommandLineParser>
+#include <QCoreApplication>
+#include <QFile>
+#include <QSaveFile>
+#include <QStringList>
+#include <QTextStream>
+
+#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)
+{
+
+ QCoreApplication app(argc, argv);
+
+ 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."));
+
+ 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);
+
+ 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()));
+ }
+
+ static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
+
+ QString line1 = inputTextStream.readLine();
+ CompositeKey key1 = CompositeKey::readFromLine(line1);
+
+ CompositeKey key2;
+ if (parser.isSet("same-password")) {
+ key2 = *key1.clone();
+ }
+ else {
+ 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;
+ }
+
+ 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;
+ }
+
+ db1->merge(db2);
+
+ QSaveFile saveFile(databaseFilename1);
+ if (!saveFile.open(QIODevice::WriteOnly)) {
+ qCritical("Unable to open file %s for writing.", qPrintable(databaseFilename1));
+ 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;
+ }
+
+ qDebug("Successfully merged the database files.\n");
+ return 1;
+
+}