From 082ecc3f370ecd9b9a57b766f0b2220f3b151e2e Mon Sep 17 00:00:00 2001 From: Thomas Luzat Date: Thu, 8 Mar 2018 03:57:14 +0100 Subject: [PATCH 01/17] Fix dark tray icon option making all icons dark Introduces a separate path for tray icons which are neither locked nor unlocked. Closes #1556. --- src/core/FilePath.cpp | 10 +++++++++- src/core/FilePath.h | 1 + src/gui/MainWindow.cpp | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/core/FilePath.cpp b/src/core/FilePath.cpp index 330542eb..c6f1907a 100644 --- a/src/core/FilePath.cpp +++ b/src/core/FilePath.cpp @@ -97,6 +97,15 @@ QString FilePath::wordlistPath(const QString& name) } QIcon FilePath::applicationIcon() +{ +#ifdef KEEPASSXC_DIST_SNAP + return icon("apps", "keepassxc", false); +#else + return icon("apps", "keepassxc"); +#endif +} + +QIcon FilePath::trayIcon() { bool darkIcon = useDarkIcon(); @@ -107,7 +116,6 @@ QIcon FilePath::applicationIcon() #endif } - QIcon FilePath::trayIconLocked() { #ifdef KEEPASSXC_DIST_SNAP diff --git a/src/core/FilePath.h b/src/core/FilePath.h index f84f84e0..b0f0397e 100644 --- a/src/core/FilePath.h +++ b/src/core/FilePath.h @@ -29,6 +29,7 @@ public: QString pluginPath(const QString& name); QString wordlistPath(const QString& name); QIcon applicationIcon(); + QIcon trayIcon(); QIcon trayIconLocked(); QIcon trayIconUnlocked(); QIcon icon(const QString& category, const QString& name, bool fromTheme = true); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 1822c48d..301b80c4 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -899,7 +899,7 @@ void MainWindow::updateTrayIcon() m_trayIcon->setContextMenu(menu); - m_trayIcon->setIcon(filePath()->applicationIcon()); + m_trayIcon->setIcon(filePath()->trayIcon()); m_trayIcon->show(); } if (m_ui->tabWidget->hasLockableDatabases()) { From f164847f9bd20603475c5866227607e154fe3358 Mon Sep 17 00:00:00 2001 From: Alessio Di Mauro Date: Thu, 8 Mar 2018 16:24:11 +0100 Subject: [PATCH 02/17] Replace in.readLine() with Utils::getPassword() Fixes #1673. --- src/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index a7fd2d76..33aa5edd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,8 @@ #include "gui/MainWindow.h" #include "gui/MessageBox.h" +#include "cli/Utils.h" + #if defined(WITH_ASAN) && defined(WITH_LSAN) #include #endif @@ -148,7 +150,9 @@ int main(int argc, char** argv) // we always need consume a line of STDIN if --pw-stdin is set to clear out the // buffer for native messaging, even if the specified file does not exist static QTextStream in(stdin, QIODevice::ReadOnly); - password = in.readLine(); + static QTextStream out(stdout, QIODevice::WriteOnly); + out << QCoreApplication::translate("Main", "Database password: ") << flush; + password = Utils::getPassword(); } if (!filename.isEmpty() && QFile::exists(filename) && !filename.endsWith(".json", Qt::CaseInsensitive)) { From 2b91e4d27c562409b460c2e7b6d0596f7d374579 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Fri, 9 Mar 2018 21:36:33 +0100 Subject: [PATCH 03/17] Fix inconsistent mutex unlocking due to double slot execution, fixes #1561 --- src/autotype/AutoType.cpp | 59 ++++++++++++++++++++++----------------- src/autotype/AutoType.h | 3 +- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index aa8064ba..3f44a994 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -140,13 +140,6 @@ QStringList AutoType::windowTitles() return m_plugin->windowTitles(); } -void AutoType::resetInAutoType() -{ - m_inAutoType.unlock(); - - emit autotypeRejected(); -} - void AutoType::raiseWindow() { #if defined(Q_OS_MAC) @@ -199,9 +192,14 @@ int AutoType::callEventFilter(void* event) */ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, const QString& sequence, WId window) { + if (!m_inAutoType.tryLock()) { + return; + } + // no edit to the sequence beyond this point if (!verifyAutoTypeSyntax(sequence)) { emit autotypeRejected(); + m_inAutoType.unlock(); return; } @@ -210,6 +208,7 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c if (!parseActions(sequence, entry, actions)) { emit autotypeRejected(); + m_inAutoType.unlock(); return; } @@ -233,6 +232,7 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c if (m_plugin->activeWindow() != window) { qWarning("Active window changed, interrupting auto-type."); emit autotypeRejected(); + m_inAutoType.unlock(); return; } @@ -242,6 +242,8 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c // emit signal only if autotype performed correctly emit autotypePerformed(); + + m_inAutoType.unlock(); } /** @@ -259,13 +261,7 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow) return; } - if (!m_inAutoType.tryLock()) { - return; - } - executeAutoTypeActions(entry, hideWindow, sequences.first()); - - m_inAutoType.unlock(); } /** @@ -278,13 +274,14 @@ void AutoType::performGlobalAutoType(const QList& dbList) return; } - QString windowTitle = m_plugin->activeWindowTitle(); - - if (windowTitle.isEmpty()) { + if (!m_inGlobalAutoTypeDialog.tryLock()) { return; } - if (!m_inAutoType.tryLock()) { + QString windowTitle = m_plugin->activeWindowTitle(); + + if (windowTitle.isEmpty()) { + m_inGlobalAutoTypeDialog.unlock(); return; } @@ -303,8 +300,6 @@ void AutoType::performGlobalAutoType(const QList& dbList) } if (matchList.isEmpty()) { - m_inAutoType.unlock(); - if (qobject_cast(QCoreApplication::instance())) { auto* msgBox = new QMessageBox(); msgBox->setAttribute(Qt::WA_DeleteOnClose); @@ -318,16 +313,20 @@ void AutoType::performGlobalAutoType(const QList& dbList) msgBox->activateWindow(); } + m_inGlobalAutoTypeDialog.unlock(); emit autotypeRejected(); } else if ((matchList.size() == 1) && !config()->get("security/autotypeask").toBool()) { executeAutoTypeActions(matchList.first().entry, nullptr, matchList.first().sequence); - m_inAutoType.unlock(); + m_inGlobalAutoTypeDialog.unlock(); } else { m_windowFromGlobal = m_plugin->activeWindow(); auto* selectDialog = new AutoTypeSelectDialog(); + + // connect slots, both of which must unlock the m_inGlobalAutoTypeDialog mutex connect(selectDialog, SIGNAL(matchActivated(AutoTypeMatch)), SLOT(performAutoTypeFromGlobal(AutoTypeMatch))); - connect(selectDialog, SIGNAL(rejected()), SLOT(resetInAutoType())); + connect(selectDialog, SIGNAL(rejected()), SLOT(autoTypeRejectedFromGlobal())); + selectDialog->setMatchList(matchList); #if defined(Q_OS_MAC) m_plugin->raiseOwnWindow(); @@ -341,14 +340,22 @@ void AutoType::performGlobalAutoType(const QList& dbList) void AutoType::performAutoTypeFromGlobal(AutoTypeMatch match) { - // We don't care about the result here, the mutex should already be locked. Now it's locked for sure - m_inAutoType.tryLock(); - m_plugin->raiseWindow(m_windowFromGlobal); - executeAutoTypeActions(match.entry, nullptr, match.sequence, m_windowFromGlobal); - m_inAutoType.unlock(); + // make sure the mutex is definitely locked before we unlock it + Q_UNUSED(m_inGlobalAutoTypeDialog.tryLock()); + m_inGlobalAutoTypeDialog.unlock(); +} + +void AutoType::autoTypeRejectedFromGlobal() +{ + // this slot can be called twice when the selection dialog is deleted, + // so make sure the mutex is locked before we try unlocking it + Q_UNUSED(m_inGlobalAutoTypeDialog.tryLock()); + m_inGlobalAutoTypeDialog.unlock(); + + emit autotypeRejected(); } /** diff --git a/src/autotype/AutoType.h b/src/autotype/AutoType.h index 98a7bd7f..55adac7d 100644 --- a/src/autotype/AutoType.h +++ b/src/autotype/AutoType.h @@ -69,7 +69,7 @@ signals: private slots: void performAutoTypeFromGlobal(AutoTypeMatch match); - void resetInAutoType(); + void autoTypeRejectedFromGlobal(); void unloadPlugin(); private: @@ -88,6 +88,7 @@ private: bool windowMatches(const QString& windowTitle, const QString& windowPattern); QMutex m_inAutoType; + QMutex m_inGlobalAutoTypeDialog; int m_autoTypeDelay; Qt::Key m_currentGlobalKey; Qt::KeyboardModifiers m_currentGlobalModifiers; From d156457405c0e61eec88e91858e7854b72826f4f Mon Sep 17 00:00:00 2001 From: Toni Spets Date: Sat, 10 Mar 2018 16:01:53 +0200 Subject: [PATCH 04/17] Always hide password on unlock Fixes #1692 --- src/gui/DatabaseOpenWidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 3af0c6e8..d011e8b6 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -173,6 +173,9 @@ void DatabaseOpenWidget::openDatabase() return; } + m_ui->editPassword->setShowPassword(false); + QCoreApplication::processEvents(); + QFile file(m_filename); if (!file.open(QIODevice::ReadOnly)) { m_ui->messageWidget->showMessage( From dc1aead2a2f36d0cbffea2e1194474bf8d5a43b0 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Wed, 7 Mar 2018 20:43:26 -0800 Subject: [PATCH 05/17] OpenSSHKey: when writing to agent, ensure comment string is at least one byte This unbreaks adding keys to gpg-agent. Signed-off-by: Steven Noonan --- src/gui/entry/EditEntryWidget.cpp | 10 +++++++++- src/sshagent/SSHAgent.cpp | 11 ++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 4d12dd16..079f8105 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -420,12 +420,16 @@ void EditEntryWidget::browsePrivateKey() bool EditEntryWidget::getOpenSSHKey(OpenSSHKey& key, bool decrypt) { + QString fileName; QByteArray privateKeyData; if (m_sshAgentUi->attachmentRadioButton->isChecked()) { - privateKeyData = m_advancedUi->attachmentsWidget->getAttachment(m_sshAgentUi->attachmentComboBox->currentText()); + fileName = m_sshAgentUi->attachmentComboBox->currentText(); + privateKeyData = m_advancedUi->attachmentsWidget->getAttachment(fileName); } else { QFile localFile(m_sshAgentUi->externalFileEdit->text()); + QFileInfo localFileInfo(localFile); + fileName = localFileInfo.fileName(); if (localFile.fileName().isEmpty()) { return false; @@ -464,6 +468,10 @@ bool EditEntryWidget::getOpenSSHKey(OpenSSHKey& key, bool decrypt) key.setComment(m_entry->username()); } + if (key.comment().isEmpty()) { + key.setComment(fileName); + } + return true; } diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index 45d774aa..36a16b20 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -268,10 +268,15 @@ void SSHAgent::databaseModeChanged(DatabaseWidget::Mode mode) } QByteArray keyData; + QString fileName; if (settings.selectedType() == "attachment") { - keyData = e->attachments()->value(settings.attachmentName()); + fileName = settings.attachmentName(); + keyData = e->attachments()->value(fileName); } else if (!settings.fileName().isEmpty()) { QFile file(settings.fileName()); + QFileInfo fileInfo(file); + + fileName = fileInfo.fileName(); if (file.size() > 1024 * 1024) { continue; @@ -302,6 +307,10 @@ void SSHAgent::databaseModeChanged(DatabaseWidget::Mode mode) key.setComment(e->username()); } + if (key.comment().isEmpty()) { + key.setComment(fileName); + } + if (settings.removeAtDatabaseClose()) { removeIdentityAtLock(key, uuid); } From 46099fdd719ed4296a98b820dfb11446a404bb0a Mon Sep 17 00:00:00 2001 From: Thomas Luzat Date: Thu, 8 Mar 2018 03:35:06 +0100 Subject: [PATCH 06/17] SSH Agent: Update available attachments immediately The list of available attachments for SSH agent is now updated immediately when adding or removing file attachments. Closes #1668. --- src/gui/entry/EditEntryWidget.cpp | 43 ++++++++++++++++++------------- src/gui/entry/EditEntryWidget.h | 1 + 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 079f8105..7acd3af3 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -281,6 +281,8 @@ void EditEntryWidget::setupSSHAgent() connect(m_sshAgentUi->decryptButton, SIGNAL(clicked()), SLOT(decryptPrivateKey())); connect(m_sshAgentUi->copyToClipboardButton, SIGNAL(clicked()), SLOT(copyPublicKey())); + connect(m_advancedUi->attachmentsWidget->entryAttachments(), SIGNAL(modified()), SLOT(updateAttachments())); + addPage(tr("SSH Agent"), FilePath::instance()->icon("apps", "utilities-terminal"), m_sshAgentWidget); } @@ -299,6 +301,27 @@ void EditEntryWidget::updateSSHAgent() m_sshAgentUi->removeFromAgentButton->setEnabled(false); m_sshAgentUi->copyToClipboardButton->setEnabled(false); + m_sshAgentSettings = settings; + updateSSHAgentAttachments(); + + if (settings.selectedType() == "attachment") { + m_sshAgentUi->attachmentRadioButton->setChecked(true); + } else { + m_sshAgentUi->externalFileRadioButton->setChecked(true); + } + + updateSSHAgentKeyInfo(); +} + +void EditEntryWidget::updateSSHAgentAttachment() +{ + m_sshAgentUi->attachmentRadioButton->setChecked(true); + updateSSHAgentKeyInfo(); +} + +void EditEntryWidget::updateSSHAgentAttachments() +{ + m_sshAgentUi->attachmentComboBox->clear(); m_sshAgentUi->attachmentComboBox->addItem(""); auto attachments = m_advancedUi->attachmentsWidget->entryAttachments(); @@ -310,24 +333,8 @@ void EditEntryWidget::updateSSHAgent() m_sshAgentUi->attachmentComboBox->addItem(fileName); } - m_sshAgentUi->attachmentComboBox->setCurrentText(settings.attachmentName()); - m_sshAgentUi->externalFileEdit->setText(settings.fileName()); - - if (settings.selectedType() == "attachment") { - m_sshAgentUi->attachmentRadioButton->setChecked(true); - } else { - m_sshAgentUi->externalFileRadioButton->setChecked(true); - } - - m_sshAgentSettings = settings; - - updateSSHAgentKeyInfo(); -} - -void EditEntryWidget::updateSSHAgentAttachment() -{ - m_sshAgentUi->attachmentRadioButton->setChecked(true); - updateSSHAgentKeyInfo(); + m_sshAgentUi->attachmentComboBox->setCurrentText(m_sshAgentSettings.attachmentName()); + m_sshAgentUi->externalFileEdit->setText(m_sshAgentSettings.fileName()); } void EditEntryWidget::updateSSHAgentKeyInfo() diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index a7c8e327..9b2a919c 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -103,6 +103,7 @@ private slots: #ifdef WITH_XC_SSHAGENT void updateSSHAgent(); void updateSSHAgentAttachment(); + void updateSSHAgentAttachments(); void updateSSHAgentKeyInfo(); void browsePrivateKey(); void addKeyToAgent(); From 64f5ee63999d4c41cb0b944518333e9a62771c0b Mon Sep 17 00:00:00 2001 From: Thomas Luzat Date: Wed, 7 Mar 2018 23:39:38 +0100 Subject: [PATCH 07/17] SSH Agent: Helpful error message for adding keys This adds more helpful error messages when adding keys to an agent fails. Closes #1667. --- src/sshagent/SSHAgent.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/sshagent/SSHAgent.cpp b/src/sshagent/SSHAgent.cpp index 36a16b20..973e0305 100644 --- a/src/sshagent/SSHAgent.cpp +++ b/src/sshagent/SSHAgent.cpp @@ -186,7 +186,17 @@ bool SSHAgent::addIdentity(OpenSSHKey& key, quint32 lifetime, bool confirm) } if (responseData.length() < 1 || static_cast(responseData[0]) != SSH_AGENT_SUCCESS) { - m_error = tr("Agent refused this identity."); + m_error = tr("Agent refused this identity. Possible reasons include:") + + "\n" + tr("The key has already been added."); + + if (lifetime > 0) { + m_error += "\n" + tr("Restricted lifetime is not supported by the agent (check options)."); + } + + if (confirm) { + m_error += "\n" + tr("A confirmation request is not supported by the agent (check options)."); + } + return false; } From f620ad979f808eca9160d6f72ab3ac8647404a7a Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sun, 11 Mar 2018 10:32:23 +0200 Subject: [PATCH 08/17] Fix extension URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f81795c..b09a5d20 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ so please check out your distribution's package list to see if KeePassXC is avai [Mozilla Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepasshttp-connector/) and [Google Chrome or Chromium](https://chrome.google.com/webstore/detail/keepasshttp-connector/dafgdjggglmmknipkhngniifhplpcldb), and [passafari](https://github.com/mmichaa/passafari.safariextension/) in Safari. [[See note about KeePassHTTP]](#Note_about_KeePassHTTP) -- Browser integration with KeePassXC-Browser using [native messaging](https://developer.chrome.com/extensions/nativeMessaging) for [Mozilla Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/) and [Google Chrome or Chromium](https://chrome.google.com/webstore/detail/keepassxc-browser/iopaggbpplllidnfmcghoonnokmjoicf) +- Browser integration with KeePassXC-Browser using [native messaging](https://developer.chrome.com/extensions/nativeMessaging) for [Mozilla Firefox](https://addons.mozilla.org/en-US/firefox/addon/keepassxc-browser/) and [Google Chrome or Chromium](https://chrome.google.com/webstore/detail/keepassxc-browser/oboonakemofpalcgghocfoadofidjkkk) - Many bug fixes For a full list of features and changes, read the [CHANGELOG](CHANGELOG) document. From 319c8201befeb4f6bed42fdc583b64370f4be828 Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 14:03:48 +0100 Subject: [PATCH 09/17] Fix flickering & not restoring from tray on some Linuxes (#1595). Fix/work around KeePassXC flickering and not restoring from tray on some Linux systems, which happens if the window is hidden and minimized by code at the same time (see issue #1595). --- src/gui/MainWindow.cpp | 3 --- src/main.cpp | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 301b80c4..3cbc4324 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -971,9 +971,6 @@ void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) void MainWindow::hideWindow() { saveWindowInformation(); -#ifndef Q_OS_MAC - setWindowState(windowState() | Qt::WindowMinimized); -#endif QTimer::singleShot(0, this, SLOT(hide())); if (config()->get("security/lockdatabaseminimize").toBool()) { diff --git a/src/main.cpp b/src/main.cpp index 33aa5edd..f09e80df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,7 +127,7 @@ int main(int argc, char** argv) // start minimized if configured bool minimizeOnStartup = config()->get("GUI/MinimizeOnStartup").toBool(); bool minimizeToTray = config()->get("GUI/MinimizeToTray").toBool(); - if (minimizeOnStartup) { + if (minimizeOnStartup && !minimizeToTray) { mainWindow.setWindowState(Qt::WindowMinimized); } if (!(minimizeOnStartup && minimizeToTray)) { From 467867016dcf8207475a606d6406b592385b9ed7 Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 14:04:33 +0100 Subject: [PATCH 10/17] Fix toggle window from tray can't hide the window on Windows (#1595) Fix unreliable check on toggleWindow() which causes Windows systems to be unable to hide the window by clicking on the tray icon (see issue #1595). --- src/gui/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 3cbc4324..3c780fa1 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -980,7 +980,7 @@ void MainWindow::hideWindow() void MainWindow::toggleWindow() { - if ((QApplication::activeWindow() == this) && isVisible() && !isMinimized()) { + if (isVisible() && !isMinimized()) { hideWindow(); } else { bringToFront(); From bf9c1b3205c59acca85dd75451146d15945668dd Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 14:05:07 +0100 Subject: [PATCH 11/17] Cover the fix/WA for Linux #1595 behind compile time flags & comment. --- src/gui/MainWindow.cpp | 6 ++++++ src/main.cpp | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 3c780fa1..f773e15b 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -971,6 +971,12 @@ void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) void MainWindow::hideWindow() { saveWindowInformation(); +#ifndef Q_OS_LINUX + // On some Linux systems, the window should NOT be minimized and hidden (i.e. not shown), at + // the same time (which would happen if both minimize on startup and minimize to tray are set) + // since otherwise it causes problems on restore as seen on issue #1595. Hiding it is enough. + setWindowState(windowState() | Qt::WindowMinimized); +#endif QTimer::singleShot(0, this, SLOT(hide())); if (config()->get("security/lockdatabaseminimize").toBool()) { diff --git a/src/main.cpp b/src/main.cpp index f09e80df..b3b607f2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,7 +127,14 @@ int main(int argc, char** argv) // start minimized if configured bool minimizeOnStartup = config()->get("GUI/MinimizeOnStartup").toBool(); bool minimizeToTray = config()->get("GUI/MinimizeToTray").toBool(); +#ifndef Q_OS_LINUX + if (minimizeOnStartup) { +#else + // On some Linux systems, the window should NOT be minimized and hidden (i.e. not shown), at + // the same time (which would happen if both minimize on startup and minimize to tray are set) + // since otherwise it causes problems on restore as seen on issue #1595. Hiding it is enough. if (minimizeOnStartup && !minimizeToTray) { +#endif mainWindow.setWindowState(Qt::WindowMinimized); } if (!(minimizeOnStartup && minimizeToTray)) { From 8646586c1a8f1523dbb3c1edf3aaf7682edf9bb6 Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 15:29:48 +0100 Subject: [PATCH 12/17] Add GUI test for issue #1595 (minus the minimize at startup case). --- tests/gui/TestGui.cpp | 25 +++++++++++++++++++++++++ tests/gui/TestGui.h | 1 + 2 files changed, 26 insertions(+) diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index b2ccd332..25c6f0c7 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -71,6 +71,8 @@ void TestGui::initTestCase() Config::createTempFileInstance(); // Disable autosave so we can test the modified file indicator Config::instance()->set("AutoSaveAfterEveryChange", false); + // Enable the tray icon so we can test hiding/restoring the window + Config::instance()->set("GUI/ShowTrayIcon", true); m_mainWindow = new MainWindow(); m_tabWidget = m_mainWindow->findChild("tabWidget"); @@ -1091,6 +1093,29 @@ void TestGui::testDragAndDropKdbxFiles() QCOMPARE(m_tabWidget->count(), openedDatabasesCount); } +void TestGui::testTrayRestoreHide() +{ + QSystemTrayIcon *trayIcon = m_mainWindow->findChild(); + + QVERIFY(m_mainWindow->isVisible()); + + trayIcon->activated(QSystemTrayIcon::Trigger); + Tools::wait(100); + QVERIFY(!m_mainWindow->isVisible()); + + trayIcon->activated(QSystemTrayIcon::Trigger); + Tools::wait(100); + QVERIFY(m_mainWindow->isVisible()); + + trayIcon->activated(QSystemTrayIcon::Trigger); + Tools::wait(100); + QVERIFY(!m_mainWindow->isVisible()); + + trayIcon->activated(QSystemTrayIcon::Trigger); + Tools::wait(100); + QVERIFY(m_mainWindow->isVisible()); +} + void TestGui::cleanupTestCase() { delete m_mainWindow; diff --git a/tests/gui/TestGui.h b/tests/gui/TestGui.h index 0b403731..e7232cca 100644 --- a/tests/gui/TestGui.h +++ b/tests/gui/TestGui.h @@ -63,6 +63,7 @@ private slots: void testKeePass1Import(); void testDatabaseLocking(); void testDragAndDropKdbxFiles(); + void testTrayRestoreHide(); private: int addCannedEntries(); From f305517724cff7fad84eff5798228fcd6058e1a7 Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 16:27:26 +0100 Subject: [PATCH 13/17] Skip the tray restore/hide test of #1595 if there's no tray (fix CI build). --- tests/gui/TestGui.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 25c6f0c7..54203c28 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -1095,8 +1095,11 @@ void TestGui::testDragAndDropKdbxFiles() void TestGui::testTrayRestoreHide() { - QSystemTrayIcon *trayIcon = m_mainWindow->findChild(); + if (!QSystemTrayIcon::isSystemTrayAvailable()) { + QSKIP("QSystemTrayIcon::isSystemTrayAvailable() = false, skipping tray restore/hide test..."); + } + QSystemTrayIcon* trayIcon = m_mainWindow->findChild(); QVERIFY(m_mainWindow->isVisible()); trayIcon->activated(QSystemTrayIcon::Trigger); From 970cedf972c573d76219529bdd6d60f20a35b072 Mon Sep 17 00:00:00 2001 From: Joan Bruguera Date: Sun, 11 Mar 2018 19:03:39 +0100 Subject: [PATCH 14/17] Add again wrongly removed conditional macro for Mac. Add again the wrongly removed conditional macro for Mac, along with a TODO asking for further documentation on its significance. --- src/gui/MainWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index f773e15b..395189d1 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -971,10 +971,11 @@ void MainWindow::trayIconTriggered(QSystemTrayIcon::ActivationReason reason) void MainWindow::hideWindow() { saveWindowInformation(); -#ifndef Q_OS_LINUX +#if !defined(Q_OS_LINUX) && !defined(Q_OS_MAC) // On some Linux systems, the window should NOT be minimized and hidden (i.e. not shown), at // the same time (which would happen if both minimize on startup and minimize to tray are set) // since otherwise it causes problems on restore as seen on issue #1595. Hiding it is enough. + // TODO: Add an explanation for why this is also not done on Mac (or remove the check) setWindowState(windowState() | Qt::WindowMinimized); #endif QTimer::singleShot(0, this, SLOT(hide())); From 3353b329fc2f91e9c97cac37b827217de79e0edf Mon Sep 17 00:00:00 2001 From: Olivier Le Moal Date: Tue, 13 Mar 2018 00:22:38 +0100 Subject: [PATCH 15/17] Fix wrong reply size in NativeMessagingBase * Using length() on QString won't return correct size in bytes when string contains UTF-8 chars. --- src/browser/NativeMessagingBase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/browser/NativeMessagingBase.cpp b/src/browser/NativeMessagingBase.cpp index 743953e9..f61a3604 100644 --- a/src/browser/NativeMessagingBase.cpp +++ b/src/browser/NativeMessagingBase.cpp @@ -121,7 +121,8 @@ void NativeMessagingBase::sendReply(const QJsonObject& json) void NativeMessagingBase::sendReply(const QString& reply) { if (!reply.isEmpty()) { - uint len = reply.length(); + QByteArray bytes = reply.toUtf8(); + uint len = bytes.size(); std::cout << char(((len>>0) & 0xFF)) << char(((len>>8) & 0xFF)) << char(((len>>16) & 0xFF)) << char(((len>>24) & 0xFF)); std::cout << reply.toStdString() << std::flush; } From 123701080dbb8821c776a69f47b4e5b20ef79f08 Mon Sep 17 00:00:00 2001 From: Piraty Date: Wed, 14 Mar 2018 18:11:33 +0100 Subject: [PATCH 16/17] Keep openSSH-portable's blowfish code unmodified and use a stub "includes.h". This also fixes build issues against musl-libc, which does not implicitly include --- src/sshagent/blf.h | 12 +----------- src/sshagent/blowfish.c | 4 ++-- src/sshagent/includes.h | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 src/sshagent/includes.h diff --git a/src/sshagent/blf.h b/src/sshagent/blf.h index 4878e558..f1ac5a5c 100644 --- a/src/sshagent/blf.h +++ b/src/sshagent/blf.h @@ -34,17 +34,7 @@ #ifndef _BLF_H_ #define _BLF_H_ -#ifdef _WIN32 - -#include - -typedef uint32_t u_int32_t; -typedef uint16_t u_int16_t; -typedef uint8_t u_int8_t; - -#define bzero(p,s) memset(p, 0, s) - -#endif +#include "includes.h" #if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) diff --git a/src/sshagent/blowfish.c b/src/sshagent/blowfish.c index 02e9ac0b..e10f7e7d 100644 --- a/src/sshagent/blowfish.c +++ b/src/sshagent/blowfish.c @@ -39,7 +39,7 @@ * Bruce Schneier. */ -#define HAVE_BLF_H +#include "includes.h" #if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \ !defined(HAVE_BLOWFISH_EXPAND0STATE) || !defined(HAVE_BLF_ENC)) @@ -51,7 +51,7 @@ #include #ifdef HAVE_BLF_H -#include "blf.h" +#include #endif #undef inline diff --git a/src/sshagent/includes.h b/src/sshagent/includes.h new file mode 100644 index 00000000..c6bb4d32 --- /dev/null +++ b/src/sshagent/includes.h @@ -0,0 +1,20 @@ +// mimic openSSH-portable's includes.h file to be able to use +// its unmodified blowfish code + +#define HAVE_BLF_H + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* activate extra prototypes for glibc */ +#endif +#include + + +#ifdef _WIN32 +#include + +typedef uint32_t u_int32_t; +typedef uint16_t u_int16_t; +typedef uint8_t u_int8_t; + +#define bzero(p,s) memset(p, 0, s) +#endif From 4a207f079bd89bed68980d55634a6abcac78aa8d Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 17 Mar 2018 11:47:28 -0400 Subject: [PATCH 17/17] Enable high entropy ASLR for Windows builds --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8929ae..a4593356 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -245,8 +245,8 @@ if(MINGW) set(CMAKE_RC_COMPILE_OBJECT " -O coff -i -o ") if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")) # Enable DEP and ASLR - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase -Wl,--high-entropy-va") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--nxcompat -Wl,--dynamicbase -Wl,--high-entropy-va") endif() endif()