From 6927158daaec26f16242af2a33e8873abf41032e Mon Sep 17 00:00:00 2001 From: TheZ3ro Date: Fri, 11 Nov 2016 22:26:07 +0100 Subject: [PATCH] Add unlock dialog on Autotype and show default Autotype sequence (#89) * Add unlockdialog on autotype. Fix #10 * Show default autotype sequence for existing entries * NOTE: New entries/groups do not show the default autotype sequence --- src/CMakeLists.txt | 1 + src/autotype/AutoType.cpp | 7 ++-- src/core/Entry.cpp | 29 ++++++++++++++++ src/core/Entry.h | 1 + src/core/Group.cpp | 17 ++++++++++ src/core/Group.h | 1 + src/gui/DatabaseTabWidget.cpp | 8 ++++- src/gui/DatabaseWidget.cpp | 35 +++++++++++++++++-- src/gui/DatabaseWidget.h | 4 +++ src/gui/UnlockDatabaseDialog.cpp | 56 +++++++++++++++++++++++++++++++ src/gui/UnlockDatabaseDialog.h | 49 +++++++++++++++++++++++++++ src/gui/entry/EditEntryWidget.cpp | 3 +- src/gui/group/EditGroupWidget.cpp | 2 +- 13 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 src/gui/UnlockDatabaseDialog.cpp create mode 100644 src/gui/UnlockDatabaseDialog.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f25ad920..eebe06f74 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -105,6 +105,7 @@ set(keepassx_SOURCES gui/SearchWidget.cpp gui/SortFilterHideProxyModel.cpp gui/UnlockDatabaseWidget.cpp + gui/UnlockDatabaseDialog.cpp gui/WelcomeWidget.cpp gui/entry/AutoTypeAssociationsModel.cpp gui/entry/EditEntryWidget.cpp diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index e48191902..696f5e1ba 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -192,9 +192,6 @@ void AutoType::performGlobalAutoType(const QList& dbList) QList entryList; QHash sequenceHash; - // TODO: Check if there are any active databases here, if not do nothing - // TODO: Check if all databases are locked, if so ask to unlock them - for (Database* db : dbList) { const QList dbEntries = db->rootGroup()->entriesRecursive(); for (Entry* entry : dbEntries) { @@ -316,7 +313,7 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList AutoType::createActionFromTemplate(const QString& tmpl, c else if (tmplName == "ptrsc") { list.append(new AutoTypeKey(Qt::Key_Print)); } - else if (tmplName == "scolllock") { + else if (tmplName == "scrolllock") { list.append(new AutoTypeKey(Qt::Key_ScrollLock)); } // Qt doesn't know about keypad keys so use the normal ones instead diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index d90a33fe8..6862fc9d8 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -185,6 +185,35 @@ QString Entry::defaultAutoTypeSequence() const return m_data.defaultAutoTypeSequence; } +QString Entry::effectiveAutoTypeSequence() const +{ + if (!m_data.defaultAutoTypeSequence.isEmpty()) { + return m_data.defaultAutoTypeSequence; + } + QString sequence; + + const Group* grp = group(); + if(grp) { + sequence = grp->effectiveAutoTypeSequence(); + } else { + return QString(); + } + + if (sequence.isEmpty() && (!username().isEmpty() || !password().isEmpty())) { + if (username().isEmpty()) { + sequence = "{PASSWORD}{ENTER}"; + } + else if (password().isEmpty()) { + sequence = "{USERNAME}{ENTER}"; + } + else { + sequence = "{USERNAME}{TAB}{PASSWORD}{ENTER}"; + } + } + + return sequence; +} + AutoTypeAssociations* Entry::autoTypeAssociations() { return m_autoTypeAssociations; diff --git a/src/core/Entry.h b/src/core/Entry.h index 0b4d4829f..910146968 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -70,6 +70,7 @@ public: bool autoTypeEnabled() const; int autoTypeObfuscation() const; QString defaultAutoTypeSequence() const; + QString effectiveAutoTypeSequence() const; AutoTypeAssociations* autoTypeAssociations(); const AutoTypeAssociations* autoTypeAssociations() const; QString title() const; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 70260170a..eb293a935 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -187,6 +187,23 @@ QString Group::defaultAutoTypeSequence() const return m_data.defaultAutoTypeSequence; } +QString Group::effectiveAutoTypeSequence() const +{ + QString sequence; + + const Group* group = this; + do { + if (group->autoTypeEnabled() == Group::Disable) { + return QString(); + } + + sequence = group->defaultAutoTypeSequence(); + group = group->parentGroup(); + } while (group && sequence.isEmpty()); + + return sequence; +} + Group::TriState Group::autoTypeEnabled() const { return m_data.autoTypeEnabled; diff --git a/src/core/Group.h b/src/core/Group.h index 025814b6c..3c054f976 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -66,6 +66,7 @@ public: TimeInfo timeInfo() const; bool isExpanded() const; QString defaultAutoTypeSequence() const; + QString effectiveAutoTypeSequence() const; Group::TriState autoTypeEnabled() const; Group::TriState searchingEnabled() const; Group::MergeMode mergeMode() const; diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 6e8a7b744..d4001501d 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -37,6 +37,7 @@ #include "gui/MessageBox.h" #include "gui/entry/EntryView.h" #include "gui/group/GroupView.h" +#include "gui/UnlockDatabaseDialog.h" DatabaseManagerStruct::DatabaseManagerStruct() : dbWidget(nullptr) @@ -235,6 +236,7 @@ bool DatabaseTabWidget::closeDatabase(Database* db) int index = databaseIndex(db); Q_ASSERT(index != -1); + dbStruct.dbWidget->closeUnlockDialog(); QString dbName = tabText(index); if (dbName.right(1) == "*") { dbName.chop(1); @@ -813,5 +815,9 @@ void DatabaseTabWidget::performGlobalAutoType() } } - autoType()->performGlobalAutoType(unlockedDatabases); + if (unlockedDatabases.size() > 0) { + autoType()->performGlobalAutoType(unlockedDatabases); + } else if (m_dbList.size() > 0){ + indexDatabaseManagerStruct(0).dbWidget->showUnlockDialog(); + } } diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index e330d99d0..7c899d3ac 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -43,6 +43,7 @@ #include "gui/KeePass1OpenWidget.h" #include "gui/MessageBox.h" #include "gui/UnlockDatabaseWidget.h" +#include "gui/UnlockDatabaseDialog.h" #include "gui/entry/EditEntryWidget.h" #include "gui/entry/EntryView.h" #include "gui/group/EditGroupWidget.h" @@ -124,6 +125,8 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) m_keepass1OpenWidget->setObjectName("keepass1OpenWidget"); m_unlockDatabaseWidget = new UnlockDatabaseWidget(); m_unlockDatabaseWidget->setObjectName("unlockDatabaseWidget"); + m_unlockDatabaseDialog = new UnlockDatabaseDialog(); + m_unlockDatabaseDialog->setObjectName("unlockDatabaseDialog"); addWidget(m_mainWidget); addWidget(m_editEntryWidget); addWidget(m_editGroupWidget); @@ -153,6 +156,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent) connect(m_databaseOpenMergeWidget, SIGNAL(editFinished(bool)), SLOT(mergeDatabase(bool))); connect(m_keepass1OpenWidget, SIGNAL(editFinished(bool)), SLOT(openDatabase(bool))); connect(m_unlockDatabaseWidget, SIGNAL(editFinished(bool)), SLOT(unlockDatabase(bool))); + connect(m_unlockDatabaseDialog, SIGNAL(unlockDone(bool)), SLOT(unlockDatabase(bool))); connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged())); m_searchCaseSensitive = false; @@ -173,7 +177,8 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() const else if (currentWidget() == m_mainWidget) { return DatabaseWidget::ViewMode; } - else if (currentWidget() == m_unlockDatabaseWidget) { + else if (currentWidget() == m_unlockDatabaseWidget || + currentWidget() == m_databaseOpenWidget) { return DatabaseWidget::LockedMode; } else { @@ -696,7 +701,14 @@ void DatabaseWidget::unlockDatabase(bool accepted) return; } - replaceDatabase(static_cast(sender())->database()); + Database *db = Q_NULLPTR; + if (sender() == m_unlockDatabaseDialog) { + db = m_unlockDatabaseDialog->database(); + } else if (sender() == m_unlockDatabaseWidget) { + db = m_unlockDatabaseWidget->database(); + } + + replaceDatabase(db); const QList groups = m_db->rootGroup()->groupsRecursive(true); for (Group* group : groups) { @@ -710,6 +722,12 @@ void DatabaseWidget::unlockDatabase(bool accepted) setCurrentWidget(m_mainWidget); m_unlockDatabaseWidget->clearForms(); Q_EMIT unlockedDatabase(); + + if (sender() == m_unlockDatabaseDialog) { + QList dbList; + dbList.append(m_db); + autoType()->performGlobalAutoType(dbList); + } } void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::ModelColumn column) @@ -1009,3 +1027,16 @@ GroupView* DatabaseWidget::groupView() { EntryView* DatabaseWidget::entryView() { return m_entryView; } + +void DatabaseWidget::showUnlockDialog() +{ + m_unlockDatabaseDialog->clearForms(); + m_unlockDatabaseDialog->setDBFilename(m_filename); + m_unlockDatabaseDialog->show(); + m_unlockDatabaseDialog->activateWindow(); +} + +void DatabaseWidget::closeUnlockDialog() +{ + m_unlockDatabaseDialog->close(); +} diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 8aa773fa2..7e0c7013f 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -41,6 +41,7 @@ class QMenu; class QSplitter; class QLabel; class UnlockDatabaseWidget; +class UnlockDatabaseDialog; class DatabaseWidget : public QStackedWidget { @@ -86,6 +87,8 @@ public: bool currentEntryHasNotes(); GroupView* groupView(); EntryView* entryView(); + void showUnlockDialog(); + void closeUnlockDialog(); Q_SIGNALS: void closeRequest(); @@ -168,6 +171,7 @@ private: DatabaseOpenWidget* m_databaseOpenMergeWidget; KeePass1OpenWidget* m_keepass1OpenWidget; UnlockDatabaseWidget* m_unlockDatabaseWidget; + UnlockDatabaseDialog* m_unlockDatabaseDialog; QSplitter* m_splitter; GroupView* m_groupView; EntryView* m_entryView; diff --git a/src/gui/UnlockDatabaseDialog.cpp b/src/gui/UnlockDatabaseDialog.cpp new file mode 100644 index 000000000..679493903 --- /dev/null +++ b/src/gui/UnlockDatabaseDialog.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "UnlockDatabaseDialog.h" +#include "UnlockDatabaseWidget.h" + +#include "autotype/AutoType.h" +#include "gui/DragTabBar.h" +#include "core/Database.h" + + +UnlockDatabaseDialog::UnlockDatabaseDialog(QWidget *parent) + : QDialog(parent) + , m_view(new UnlockDatabaseWidget(this)) +{ + connect(m_view, SIGNAL(editFinished(bool)), this, SLOT(complete(bool))); +} + +void UnlockDatabaseDialog::setDBFilename(const QString &filename) +{ + m_view->load(filename); +} + +void UnlockDatabaseDialog::clearForms() +{ + m_view->clearForms(); +} + +Database *UnlockDatabaseDialog::database() +{ + return m_view->database(); +} + +void UnlockDatabaseDialog::complete(bool r) +{ + if (r) { + accept(); + Q_EMIT unlockDone(true); + } else { + reject(); + } +} diff --git a/src/gui/UnlockDatabaseDialog.h b/src/gui/UnlockDatabaseDialog.h new file mode 100644 index 000000000..1ba6d2e06 --- /dev/null +++ b/src/gui/UnlockDatabaseDialog.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 KeePassXC Team + * + * 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 . + */ + +#ifndef KEEPASSX_AUTOTYPEUNLOCKDIALOG_H +#define KEEPASSX_AUTOTYPEUNLOCKDIALOG_H + +#include + +//#include + +#include "core/Global.h" + +class UnlockDatabaseWidget; +class Database; + +class UnlockDatabaseDialog : public QDialog +{ + Q_OBJECT +public: + explicit UnlockDatabaseDialog(QWidget *parent = Q_NULLPTR); + void setDBFilename(const QString& filename); + void clearForms(); + Database* database(); + +Q_SIGNALS: + void unlockDone(bool); + +public Q_SLOTS: + void complete(bool r); + +private: + UnlockDatabaseWidget* const m_view; +}; + +#endif // KEEPASSX_AUTOTYPEUNLOCKDIALOG_H diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index eb5ebd476..46b59df60 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -354,12 +354,11 @@ void EditEntryWidget::setForms(const Entry* entry, bool restore) m_autoTypeUi->enableButton->setChecked(entry->autoTypeEnabled()); if (entry->defaultAutoTypeSequence().isEmpty()) { m_autoTypeUi->inheritSequenceButton->setChecked(true); - m_autoTypeUi->sequenceEdit->setText(""); } else { m_autoTypeUi->customSequenceButton->setChecked(true); - m_autoTypeUi->sequenceEdit->setText(entry->defaultAutoTypeSequence()); } + m_autoTypeUi->sequenceEdit->setText(entry->effectiveAutoTypeSequence()); m_autoTypeUi->windowTitleCombo->lineEdit()->clear(); m_autoTypeUi->defaultWindowSequenceButton->setChecked(true); m_autoTypeUi->windowSequenceEdit->setText(""); diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index a5b426b92..177c62bb0 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -82,7 +82,7 @@ void EditGroupWidget::loadGroup(Group* group, bool create, Database* database) else { m_mainUi->autoTypeSequenceCustomRadio->setChecked(true); } - m_mainUi->autoTypeSequenceCustomEdit->setText(group->defaultAutoTypeSequence()); + m_mainUi->autoTypeSequenceCustomEdit->setText(group->effectiveAutoTypeSequence()); IconStruct iconStruct; iconStruct.uuid = group->iconUuid();