From 4e7f2c6a4fe920ec4301b110258f894fc9ea87bf Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 28 Oct 2017 09:23:45 -0400 Subject: [PATCH 1/4] Fix apply button not saving new entries --- src/gui/entry/EditEntryWidget.cpp | 4 ++- src/gui/entry/EditEntryWidget.h | 1 + tests/gui/TestGui.cpp | 58 ++++++++++++++++++++++++++++--- tests/gui/TestGui.h | 1 + 4 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 809ac95e..5a058bda 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -278,6 +278,7 @@ void EditEntryWidget::loadEntry(Entry* entry, bool create, bool history, const Q m_database = database; m_create = create; m_history = history; + m_saved = false; if (history) { setHeadline(QString("%1 > %2").arg(parentName, tr("Entry history"))); @@ -438,6 +439,7 @@ void EditEntryWidget::saveEntry() } updateEntryData(m_entry); + m_saved = true; if (!m_create) { m_entry->endUpdate(); @@ -510,7 +512,7 @@ void EditEntryWidget::cancel() clear(); - emit editFinished(false); + emit editFinished(m_saved); } void EditEntryWidget::clear() diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index 2888d43a..628f8f8e 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -121,6 +121,7 @@ private: bool m_create; bool m_history; + bool m_saved; const QScopedPointer m_mainUi; const QScopedPointer m_advancedUi; const QScopedPointer m_autoTypeUi; diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 75ce3cc5..6805e105 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -332,15 +332,27 @@ void TestGui::testAddEntry() QTest::keyClicks(passwordRepeatEdit, "something 2"); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); - // Add entry "something 3" + // Add entry "something 3" using the apply button then click ok QTest::mouseClick(entryNewWidget, Qt::LeftButton); QTest::keyClicks(titleEdit, "something 3"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Apply), Qt::LeftButton); QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + // Add entry "something 4" using the apply button then click cancel + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QTest::keyClicks(titleEdit, "something 4"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Apply), Qt::LeftButton); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton); + + // Add entry "something 5" but click cancel button (does NOT add entry) + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QTest::keyClicks(titleEdit, "something 5"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Cancel), Qt::LeftButton); + QApplication::processEvents(); - // Confirm that 4 entries now exist - QTRY_COMPARE(entryView->model()->rowCount(), 4); + // Confirm that 5 entries now exist + QTRY_COMPARE(entryView->model()->rowCount(), 5); } void TestGui::testPasswordEntryEntropy() @@ -513,7 +525,7 @@ void TestGui::testTotp() void TestGui::testSearch() { // Add canned entries for consistent testing - testAddEntry(); + Q_UNUSED(addCannedEntries()); QToolBar* toolBar = m_mainWindow->findChild("toolBar"); @@ -629,7 +641,7 @@ void TestGui::testSearch() void TestGui::testDeleteEntry() { // Add canned entries for consistent testing - testAddEntry(); + Q_UNUSED(addCannedEntries()); GroupView* groupView = m_dbWidget->findChild("groupView"); EntryView* entryView = m_dbWidget->findChild("entryView"); @@ -905,6 +917,42 @@ void TestGui::cleanupTestCase() delete m_mainWindow; } +int TestGui::addCannedEntries() +{ + int entries_added = 0; + + // Find buttons + QToolBar* toolBar = m_mainWindow->findChild("toolBar"); + QWidget* entryNewWidget = toolBar->widgetForAction(m_mainWindow->findChild("actionEntryNew")); + EditEntryWidget* editEntryWidget = m_dbWidget->findChild("editEntryWidget"); + QLineEdit* titleEdit = editEntryWidget->findChild("titleEdit"); + QLineEdit* passwordEdit = editEntryWidget->findChild("passwordEdit"); + QLineEdit* passwordRepeatEdit = editEntryWidget->findChild("passwordRepeatEdit"); + + // Add entry "test" and confirm added + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QTest::keyClicks(titleEdit, "test"); + QDialogButtonBox* editEntryWidgetButtonBox = editEntryWidget->findChild("buttonBox"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + ++entries_added; + + // Add entry "something 2" + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QTest::keyClicks(titleEdit, "something 2"); + QTest::keyClicks(passwordEdit, "something 2"); + QTest::keyClicks(passwordRepeatEdit, "something 2"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + ++entries_added; + + // Add entry "something 3" + QTest::mouseClick(entryNewWidget, Qt::LeftButton); + QTest::keyClicks(titleEdit, "something 3"); + QTest::mouseClick(editEntryWidgetButtonBox->button(QDialogButtonBox::Ok), Qt::LeftButton); + ++entries_added; + + return entries_added; +} + void TestGui::checkDatabase(QString dbFileName) { if (dbFileName.isEmpty()) diff --git a/tests/gui/TestGui.h b/tests/gui/TestGui.h index 904e5f21..352dbf21 100644 --- a/tests/gui/TestGui.h +++ b/tests/gui/TestGui.h @@ -61,6 +61,7 @@ private slots: void testDatabaseLocking(); private: + int addCannedEntries(); void checkDatabase(QString dbFileName = ""); void triggerAction(const QString& name); void dragAndDropGroup(const QModelIndex& sourceIndex, const QModelIndex& targetIndex, int row, From e17b3d24bfa19c199bcfe0ebffe0ae036378af4a Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Thu, 23 Nov 2017 12:51:02 -0500 Subject: [PATCH 2/4] Corrected database corruption when locked [#1113] --- src/gui/DatabaseTabWidget.cpp | 16 +++++++++------- src/gui/DatabaseWidget.cpp | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 4c9445cc..f70df4c7 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -298,8 +298,7 @@ bool DatabaseTabWidget::closeDatabase(Database* db) if (!saveDatabase(db)) { return false; } - } - else { + } else if (dbStruct.dbWidget->currentMode() != DatabaseWidget::LockedMode) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Save changes?"), @@ -307,10 +306,9 @@ bool DatabaseTabWidget::closeDatabase(Database* db) QMessageBox::Yes | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Yes); if (result == QMessageBox::Yes) { if (!saveDatabase(db)) { - return false; + return false; } - } - else if (result == QMessageBox::Cancel) { + } else if (result == QMessageBox::Cancel) { return false; } } @@ -355,8 +353,13 @@ bool DatabaseTabWidget::saveDatabase(Database* db) { DatabaseManagerStruct& dbStruct = m_dbList[db]; - if (dbStruct.saveToFilename) { + if (dbStruct.dbWidget->currentMode() == DatabaseWidget::LockedMode) { + // Never allow saving a locked database; it causes corruption + // We return true since a save is not required + return true; + } + if (dbStruct.saveToFilename) { dbStruct.dbWidget->blockAutoReload(true); QString errorMessage = db->saveToFile(dbStruct.canonicalFilePath); dbStruct.dbWidget->blockAutoReload(false); @@ -375,7 +378,6 @@ bool DatabaseTabWidget::saveDatabase(Database* db) MessageWidget::Error); return false; } - } else { return saveDatabaseAs(db); } diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 3a39bddc..453b2009 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -1125,7 +1125,7 @@ void DatabaseWidget::onWatchedFileChanged() void DatabaseWidget::reloadDatabaseFile() { - if (m_db == nullptr) + if (m_db == nullptr || currentMode() == DatabaseWidget::LockedMode) return; if (! config()->get("AutoReloadOnChange").toBool()) { From 8905fe5a5455f2c8d7a5b6ffddf0ae9e0116cbc8 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 26 Nov 2017 16:48:09 +0100 Subject: [PATCH 3/4] Use Consolas on Windows for PasswordEdit instead of the default Courier New, resolves #1226 --- src/gui/PasswordEdit.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/gui/PasswordEdit.cpp b/src/gui/PasswordEdit.cpp index 54b0ca28..ad736bf2 100644 --- a/src/gui/PasswordEdit.cpp +++ b/src/gui/PasswordEdit.cpp @@ -31,9 +31,18 @@ PasswordEdit::PasswordEdit(QWidget* parent) { setEchoMode(QLineEdit::Password); updateStylesheet(); - - // set font to system monospace font and increase letter spacing + + // use a monospace font for the password field QFont passwordFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); +#ifdef Q_OS_WIN + // try to use Consolas on Windows, because the default Courier New has too many similar characters + QFont consolasFont = QFontDatabase().font("Consolas", passwordFont.styleName(), passwordFont.pointSize()); + const QFont defaultFont; + if (passwordFont != defaultFont) { + passwordFont = consolasFont; + } +#endif + passwordFont.setLetterSpacing(QFont::PercentageSpacing, 110); setFont(passwordFont); } From b20918b60e810d3c946d8510c34243bc3dd242c4 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Sun, 26 Nov 2017 13:38:53 +0100 Subject: [PATCH 4/4] Add update information to AppImage and use KeePassXC PPA for YubiKey libs, resolves #1157 --- AppImage-Recipe.sh | 15 ++++++++------- Dockerfile | 37 +++++++------------------------------ 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/AppImage-Recipe.sh b/AppImage-Recipe.sh index e29c0562..a5124a74 100755 --- a/AppImage-Recipe.sh +++ b/AppImage-Recipe.sh @@ -85,14 +85,15 @@ else fi EOF chmod +x ./usr/bin/keepassxc_env -sed -i 's/Exec=keepassxc/Exec=keepassxc_env/' org.${LOWERAPP}.desktop -get_desktopintegration "org.${LOWERAPP}" - -GLIBC_NEEDED=$(glibc_needed) +sed -i 's/Exec=keepassxc/Exec=keepassxc_env/' org.${LOWERAPP}.${APP}.desktop +get_desktopintegration "org.${LOWERAPP}.${APP}" cd .. -generate_type2_appimage +GLIBC_NEEDED=$(glibc_needed) +NO_GLIBC_VERSION=true -mv ../out/*.AppImage ../KeePassXC-${VERSION}-${ARCH}.AppImage -rmdir ../out > /dev/null 2>&1 +generate_type2_appimage -u "gh-releases-zsync|keepassxreboot|keepassxc|latest|KeePassXC-*-${ARCH}.AppImage.zsync" + +mv ../out/*.AppImage* ../ +rm -rf ../out diff --git a/Dockerfile b/Dockerfile index ad9a2f44..a5966be3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,8 @@ RUN set -x \ && apt-get -y install software-properties-common RUN set -x \ - && add-apt-repository ppa:beineri/opt-qt${QT5_PPA_VERSION}-trusty + && add-apt-repository ppa:beineri/opt-qt${QT5_PPA_VERSION}-trusty \ + && add-apt-repository ppa:phoerious/keepassxc RUN set -x \ && apt-get update -y \ @@ -42,7 +43,9 @@ RUN set -x \ zlib1g-dev \ libxi-dev \ libxtst-dev \ - mesa-common-dev + mesa-common-dev \ + libyubikey-dev \ + libykpers-1-dev ENV CMAKE_PREFIX_PATH=/opt/qt${QT5_VERSION}/lib/cmake ENV LD_LIBRARY_PATH=/opt/qt${QT5_VERSION}/lib @@ -52,34 +55,8 @@ RUN set -x \ # AppImage dependencies RUN set -x \ && apt-get install -y \ - wget \ - libfuse2 - -# build libyubikey -ENV YUBIKEY_VERSION=1.13 -RUN set -x \ - && wget "https://developers.yubico.com/yubico-c/Releases/libyubikey-${YUBIKEY_VERSION}.tar.gz" \ - && tar xf libyubikey-${YUBIKEY_VERSION}.tar.gz \ - && cd libyubikey-${YUBIKEY_VERSION} \ - && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu \ - && make \ - && make install \ - && cd .. \ - && rm -Rf libyubikey-${YUBIKEY_VERSION}* - -# build libykpers-1 -ENV YKPERS_VERSION=1.18.0 -RUN set -x \ - && apt-get install -y libusb-dev -RUN set -x \ - && wget "https://developers.yubico.com/yubikey-personalization/Releases/ykpers-${YKPERS_VERSION}.tar.gz" \ - && tar xf ykpers-${YKPERS_VERSION}.tar.gz \ - && cd ykpers-${YKPERS_VERSION} \ - && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu \ - && make \ - && make install \ - && cd .. \ - && rm -Rf ykpers-${YKPERS_VERSION}* + libfuse2 \ + wget VOLUME /keepassxc/src VOLUME /keepassxc/out