From 52d411f423391ccb3b952a08afc1f6465054245b Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Tue, 26 Mar 2019 17:14:42 -0400 Subject: [PATCH 1/5] Use existing base64 check in Tools namespace --- src/format/KdbxXmlReader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/format/KdbxXmlReader.cpp b/src/format/KdbxXmlReader.cpp index 84d597bdb8..ab2b9aeb7f 100644 --- a/src/format/KdbxXmlReader.cpp +++ b/src/format/KdbxXmlReader.cpp @@ -1028,10 +1028,8 @@ bool KdbxXmlReader::readBool() QDateTime KdbxXmlReader::readDateTime() { - static QRegularExpression b64regex("^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$"); QString str = readString(); - - if (b64regex.match(str).hasMatch()) { + if (Tools::isBase64(str.toLatin1())) { QByteArray secsBytes = QByteArray::fromBase64(str.toUtf8()).leftJustified(8, '\0', true).left(8); qint64 secs = Endian::bytesToSizedInt(secsBytes, KeePass2::BYTEORDER); return QDateTime(QDate(1, 1, 1), QTime(0, 0, 0, 0), Qt::UTC).addSecs(secs); From edef225eab4698ea0a0bc6bc7996369ff5d1c6fb Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Tue, 26 Mar 2019 22:23:16 -0400 Subject: [PATCH 2/5] Fix opening files from command line * Fix #2877 - password is unchecked by default * Smarter activation of key components based on contents of text entry fields * Prevent multiple copies of the same database from opening when the canonicalFileName != fileName --- src/core/Database.cpp | 20 ++++++++++++++++++++ src/core/Database.h | 1 + src/gui/DatabaseOpenWidget.cpp | 23 +++++++++++------------ src/gui/DatabaseTabWidget.cpp | 10 +++------- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 22484cb808..cb3039cd94 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -388,11 +388,31 @@ const Metadata* Database::metadata() const return m_metadata; } +/** + * Returns the original file path that was provided for + * this database. This path may not exist, may contain + * unresolved symlinks, or have malformed slashes. + * + * @return original file path + */ QString Database::filePath() const { return m_data.filePath; } +/** + * Returns the canonical file path of this databases' + * set file path. This returns an empty string if the + * file does not exist or cannot be resolved. + * + * @return canonical file path + */ +QString Database::canonicalFilePath() const +{ + QFileInfo fileInfo(m_data.filePath); + return fileInfo.canonicalFilePath(); +} + void Database::setFilePath(const QString& filePath) { if (filePath == m_data.filePath) { diff --git a/src/core/Database.h b/src/core/Database.h index 8df2b9317e..bfdbf79153 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -82,6 +82,7 @@ class Database : public QObject QUuid uuid() const; QString filePath() const; + QString canonicalFilePath() const; void setFilePath(const QString& filePath); Metadata* metadata(); diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 1558466406..c7237a3698 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -45,7 +45,6 @@ DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent) m_ui->setupUi(this); m_ui->messageWidget->setHidden(true); - m_ui->checkPassword->setChecked(true); QFont font = m_ui->labelHeadline->font(); font.setBold(true); @@ -159,7 +158,7 @@ void DatabaseOpenWidget::clearForms() m_ui->editPassword->setText(""); m_ui->comboKeyFile->clear(); m_ui->comboKeyFile->setEditText(""); - m_ui->checkPassword->setChecked(true); + m_ui->checkPassword->setChecked(false); m_ui->checkKeyFile->setChecked(false); m_ui->checkChallengeResponse->setChecked(false); m_ui->checkTouchID->setChecked(false); @@ -174,13 +173,8 @@ QSharedPointer DatabaseOpenWidget::database() void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile) { - if (!pw.isEmpty()) { - m_ui->editPassword->setText(pw); - } - if (!keyFile.isEmpty()) { - m_ui->comboKeyFile->setEditText(keyFile); - } - + m_ui->editPassword->setText(pw); + m_ui->comboKeyFile->setEditText(keyFile); openDatabase(); } @@ -339,17 +333,20 @@ void DatabaseOpenWidget::reject() void DatabaseOpenWidget::activatePassword() { - m_ui->checkPassword->setChecked(true); + bool hasPassword = !m_ui->editPassword->text().isEmpty(); + m_ui->checkPassword->setChecked(hasPassword); } void DatabaseOpenWidget::activateKeyFile() { - m_ui->checkKeyFile->setChecked(true); + bool hasKeyFile = !m_ui->comboKeyFile->lineEdit()->text().isEmpty(); + m_ui->checkKeyFile->setChecked(hasKeyFile); } void DatabaseOpenWidget::activateChallengeResponse() { - m_ui->checkChallengeResponse->setChecked(true); + bool hasCR = m_ui->comboChallengeResponse->currentData().toInt() != -1; + m_ui->checkChallengeResponse->setChecked(hasCR); } void DatabaseOpenWidget::browseKeyFile() @@ -372,6 +369,7 @@ void DatabaseOpenWidget::pollYubikey() m_ui->checkChallengeResponse->setChecked(false); m_ui->comboChallengeResponse->setEnabled(false); m_ui->comboChallengeResponse->clear(); + m_ui->comboChallengeResponse->addItem(tr("-- SELECT --"), -1); m_ui->yubikeyProgress->setVisible(true); // YubiKey init is slow, detect asynchronously to not block the UI @@ -388,6 +386,7 @@ void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking) QHash lastChallengeResponse = config()->get("LastChallengeResponse").toHash(); if (lastChallengeResponse.contains(m_filename)) { m_ui->checkChallengeResponse->setChecked(true); + m_ui->comboChallengeResponse->setCurrentIndex(1); } } } diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 7693c90169..a7fed628b3 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -157,10 +157,8 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath, for (int i = 0, c = count(); i < c; ++i) { auto* dbWidget = databaseWidgetFromIndex(i); Q_ASSERT(dbWidget); - if (dbWidget && dbWidget->database()->filePath() == canonicalFilePath) { - if (!password.isEmpty()) { - dbWidget->performUnlockDatabase(password, keyfile); - } + if (dbWidget && dbWidget->database()->canonicalFilePath() == canonicalFilePath) { + dbWidget->performUnlockDatabase(password, keyfile); if (!inBackground) { // switch to existing tab if file is already open setCurrentIndex(indexOf(dbWidget)); @@ -171,9 +169,7 @@ void DatabaseTabWidget::addDatabaseTab(const QString& filePath, auto* dbWidget = new DatabaseWidget(QSharedPointer::create(filePath), this); addDatabaseTab(dbWidget, inBackground); - if (!password.isEmpty()) { - dbWidget->performUnlockDatabase(password, keyfile); - } + dbWidget->performUnlockDatabase(password, keyfile); updateLastDatabases(filePath); } From cb2900f5a98b3774b9dfaa4c6ead4f1a3b18c6fc Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sat, 30 Mar 2019 21:31:32 -0400 Subject: [PATCH 3/5] Fix database master key dirtying * When removing portions of the master key, the key is marked dirty for saving * Properly clear password and other fields in edit entry widget and password widgets --- src/gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp | 7 +++---- src/gui/entry/EditEntryWidget.cpp | 7 +++++++ src/gui/masterkey/PasswordEditWidget.cpp | 9 +++++++++ src/gui/masterkey/PasswordEditWidget.h | 1 + 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp index d1a64b5290..a8425aae18 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp @@ -77,11 +77,8 @@ void DatabaseSettingsWidgetMasterKey::load(QSharedPointer db) // database has no key, we are about to add a new one m_passwordEditWidget->changeVisiblePage(KeyComponentWidget::Page::Edit); m_passwordEditWidget->setPasswordVisible(true); - m_isDirty = true; - return; } - bool isDirty = false; bool hasAdditionalKeys = false; for (const auto& key : m_db->key()->keys()) { if (key->uuid() == PasswordKey::UUID) { @@ -103,7 +100,9 @@ void DatabaseSettingsWidgetMasterKey::load(QSharedPointer db) setAdditionalKeyOptionsVisible(hasAdditionalKeys); - m_isDirty = isDirty; + connect(m_passwordEditWidget->findChild("removeButton"), SIGNAL(clicked()), SLOT(markDirty())); + connect(m_keyFileEditWidget->findChild("removeButton"), SIGNAL(clicked()), SLOT(markDirty())); + connect(m_yubiKeyEditWidget->findChild("removeButton"), SIGNAL(clicked()), SLOT(markDirty())); } void DatabaseSettingsWidgetMasterKey::initialize() diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 9a4c1600f2..74a1fcd364 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -993,6 +993,13 @@ void EditEntryWidget::clear() { m_entry = nullptr; m_db.reset(); + + m_mainUi->titleEdit->setText(""); + m_mainUi->passwordEdit->setText(""); + m_mainUi->passwordRepeatEdit->setText(""); + m_mainUi->urlEdit->setText(""); + m_mainUi->notesEdit->clear(); + m_entryAttributes->clear(); m_advancedUi->attachmentsWidget->clearAttachments(); m_autoTypeAssoc->clear(); diff --git a/src/gui/masterkey/PasswordEditWidget.cpp b/src/gui/masterkey/PasswordEditWidget.cpp index 86d629da05..6f6cf4d99a 100644 --- a/src/gui/masterkey/PasswordEditWidget.cpp +++ b/src/gui/masterkey/PasswordEditWidget.cpp @@ -92,6 +92,15 @@ void PasswordEditWidget::initComponentEditWidget(QWidget* widget) m_compUi->enterPasswordEdit->setFocus(); } +void PasswordEditWidget::hideEvent(QHideEvent* event) +{ + if (!isVisible() && m_compUi->enterPasswordEdit) { + m_compUi->enterPasswordEdit->setText(""); + } + + QWidget::hideEvent(event); +} + bool PasswordEditWidget::validate(QString& errorMessage) const { if (m_compUi->enterPasswordEdit->text() != m_compUi->repeatPasswordEdit->text()) { diff --git a/src/gui/masterkey/PasswordEditWidget.h b/src/gui/masterkey/PasswordEditWidget.h index 9f3eb75cea..57c225c1fb 100644 --- a/src/gui/masterkey/PasswordEditWidget.h +++ b/src/gui/masterkey/PasswordEditWidget.h @@ -44,6 +44,7 @@ class PasswordEditWidget : public KeyComponentWidget protected: QWidget* componentEditWidget() override; void initComponentEditWidget(QWidget* widget) override; + void hideEvent(QHideEvent* event) override; private slots: void showPasswordGenerator(); From f49a8a7f70fd5cdf0da6ed555c651bfcc2cbe8ca Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Tue, 2 Apr 2019 00:01:58 +0200 Subject: [PATCH 4/5] Fix key component widget initialization and password field echo mode on database open --- src/gui/DatabaseOpenWidget.cpp | 6 ++---- src/gui/masterkey/KeyComponentWidget.cpp | 20 ++++++++++++++------ src/gui/masterkey/KeyComponentWidget.h | 5 ++++- src/gui/masterkey/PasswordEditWidget.cpp | 3 +++ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index c7237a3698..0f540bca89 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -185,9 +185,7 @@ void DatabaseOpenWidget::openDatabase() return; } - if (!m_ui->editPassword->isPasswordVisible()) { - m_ui->editPassword->setShowPassword(false); - } + m_ui->editPassword->setShowPassword(false); QCoreApplication::processEvents(); m_db.reset(new Database()); @@ -369,7 +367,7 @@ void DatabaseOpenWidget::pollYubikey() m_ui->checkChallengeResponse->setChecked(false); m_ui->comboChallengeResponse->setEnabled(false); m_ui->comboChallengeResponse->clear(); - m_ui->comboChallengeResponse->addItem(tr("-- SELECT --"), -1); + m_ui->comboChallengeResponse->addItem(tr("Select slot..."), -1); m_ui->yubikeyProgress->setVisible(true); // YubiKey init is slow, detect asynchronously to not block the UI diff --git a/src/gui/masterkey/KeyComponentWidget.cpp b/src/gui/masterkey/KeyComponentWidget.cpp index 7d795aca1a..da362a9521 100644 --- a/src/gui/masterkey/KeyComponentWidget.cpp +++ b/src/gui/masterkey/KeyComponentWidget.cpp @@ -37,7 +37,7 @@ KeyComponentWidget::KeyComponentWidget(const QString& name, QWidget* parent) connect(m_ui->removeButton, SIGNAL(clicked(bool)), SIGNAL(componentRemovalRequested())); connect(m_ui->cancelButton, SIGNAL(clicked(bool)), SLOT(cancelEdit())); - connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(reset())); + connect(m_ui->stackedWidget, SIGNAL(currentChanged(int)), SLOT(resetComponentEditWidget())); connect(this, SIGNAL(nameChanged(QString)), SLOT(updateComponentName(QString))); connect(this, SIGNAL(descriptionChanged(QString)), SLOT(updateComponentDescription(QString))); @@ -46,11 +46,13 @@ KeyComponentWidget::KeyComponentWidget(const QString& name, QWidget* parent) connect(this, SIGNAL(componentRemovalRequested()), SLOT(doRemove())); connect(this, SIGNAL(componentAddChanged(bool)), SLOT(updateAddStatus(bool))); - blockSignals(true); + bool prev = blockSignals(true); setComponentName(name); + blockSignals(prev); + + prev = m_ui->stackedWidget->blockSignals(true); m_ui->stackedWidget->setCurrentIndex(Page::AddNew); - updateSize(); - blockSignals(false); + m_ui->stackedWidget->blockSignals(prev); } KeyComponentWidget::~KeyComponentWidget() @@ -164,9 +166,15 @@ void KeyComponentWidget::cancelEdit() emit editCanceled(); } -void KeyComponentWidget::reset() +void KeyComponentWidget::showEvent(QShowEvent* event) +{ + QWidget::showEvent(event); + resetComponentEditWidget(); +} + +void KeyComponentWidget::resetComponentEditWidget() { - if (static_cast(m_ui->stackedWidget->currentIndex()) == Page::Edit) { + if (m_ui->componentWidgetLayout->isEmpty() || static_cast(m_ui->stackedWidget->currentIndex()) == Page::Edit) { if (!m_ui->componentWidgetLayout->isEmpty()) { auto* item = m_ui->componentWidgetLayout->takeAt(0); if (item->widget()) { diff --git a/src/gui/masterkey/KeyComponentWidget.h b/src/gui/masterkey/KeyComponentWidget.h index cf2ae4947d..f184c13214 100644 --- a/src/gui/masterkey/KeyComponentWidget.h +++ b/src/gui/masterkey/KeyComponentWidget.h @@ -109,6 +109,9 @@ class KeyComponentWidget : public QWidget void editCanceled(); void componentRemovalRequested(); +protected: + void showEvent(QShowEvent* event) override ; + private slots: void updateComponentName(const QString& name); void updateComponentDescription(const QString& decription); @@ -117,7 +120,7 @@ private slots: void doEdit(); void doRemove(); void cancelEdit(); - void reset(); + void resetComponentEditWidget(); void updateSize(); private: diff --git a/src/gui/masterkey/PasswordEditWidget.cpp b/src/gui/masterkey/PasswordEditWidget.cpp index 6f6cf4d99a..de00199bbf 100644 --- a/src/gui/masterkey/PasswordEditWidget.cpp +++ b/src/gui/masterkey/PasswordEditWidget.cpp @@ -94,8 +94,11 @@ void PasswordEditWidget::initComponentEditWidget(QWidget* widget) void PasswordEditWidget::hideEvent(QHideEvent* event) { + Q_ASSERT(m_compUi->enterPasswordEdit); + if (!isVisible() && m_compUi->enterPasswordEdit) { m_compUi->enterPasswordEdit->setText(""); + m_compUi->repeatPasswordEdit->setText(""); } QWidget::hideEvent(event); From e025444c869b40aec75fe90e095cd888f64d1b21 Mon Sep 17 00:00:00 2001 From: Janek Bevendorff Date: Tue, 2 Apr 2019 22:32:48 +0200 Subject: [PATCH 5/5] Fix double password edit field --- src/gui/masterkey/KeyComponentWidget.cpp | 19 +++++++------------ src/gui/masterkey/KeyComponentWidget.h | 2 ++ 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/gui/masterkey/KeyComponentWidget.cpp b/src/gui/masterkey/KeyComponentWidget.cpp index da362a9521..769cbab95c 100644 --- a/src/gui/masterkey/KeyComponentWidget.cpp +++ b/src/gui/masterkey/KeyComponentWidget.cpp @@ -168,25 +168,20 @@ void KeyComponentWidget::cancelEdit() void KeyComponentWidget::showEvent(QShowEvent* event) { - QWidget::showEvent(event); resetComponentEditWidget(); + QWidget::showEvent(event); } void KeyComponentWidget::resetComponentEditWidget() { - if (m_ui->componentWidgetLayout->isEmpty() || static_cast(m_ui->stackedWidget->currentIndex()) == Page::Edit) { - if (!m_ui->componentWidgetLayout->isEmpty()) { - auto* item = m_ui->componentWidgetLayout->takeAt(0); - if (item->widget()) { - delete item->widget(); - } - delete item; + if (!m_componentWidget || static_cast(m_ui->stackedWidget->currentIndex()) == Page::Edit) { + if (m_componentWidget) { + delete m_componentWidget; } - QWidget* widget = componentEditWidget(); - m_ui->componentWidgetLayout->addWidget(widget); - - initComponentEditWidget(widget); + m_componentWidget = componentEditWidget(); + m_ui->componentWidgetLayout->addWidget(m_componentWidget); + initComponentEditWidget(m_componentWidget); } QTimer::singleShot(0, this, SLOT(updateSize())); diff --git a/src/gui/masterkey/KeyComponentWidget.h b/src/gui/masterkey/KeyComponentWidget.h index f184c13214..63079863ed 100644 --- a/src/gui/masterkey/KeyComponentWidget.h +++ b/src/gui/masterkey/KeyComponentWidget.h @@ -20,6 +20,7 @@ #include #include +#include namespace Ui { @@ -128,6 +129,7 @@ private slots: Page m_previousPage = Page::AddNew; QString m_componentName; QString m_componentDescription; + QPointer m_componentWidget; const QScopedPointer m_ui; };