Implement database locking.

Closes #35
This commit is contained in:
Felix Geyer 2012-10-12 12:12:00 +02:00
parent 8117809901
commit e166722026
15 changed files with 297 additions and 54 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

View File

@ -82,6 +82,7 @@ set(keepassx_SOURCES
gui/MainWindow.cpp gui/MainWindow.cpp
gui/SettingsWidget.cpp gui/SettingsWidget.cpp
gui/SortFilterHideProxyModel.cpp gui/SortFilterHideProxyModel.cpp
gui/UnlockDatabaseWidget.cpp
gui/WelcomeWidget.cpp gui/WelcomeWidget.cpp
gui/entry/AutoTypeAssociationsModel.cpp gui/entry/AutoTypeAssociationsModel.cpp
gui/entry/EditEntryWidget.cpp gui/entry/EditEntryWidget.cpp
@ -137,6 +138,7 @@ set(keepassx_MOC
gui/MainWindow.h gui/MainWindow.h
gui/SettingsWidget.h gui/SettingsWidget.h
gui/SortFilterHideProxyModel.h gui/SortFilterHideProxyModel.h
gui/UnlockDatabaseWidget.h
gui/WelcomeWidget.h gui/WelcomeWidget.h
gui/entry/AutoTypeAssociationsModel.h gui/entry/AutoTypeAssociationsModel.h
gui/entry/EditEntryWidget.h gui/entry/EditEntryWidget.h

View File

@ -94,30 +94,10 @@ void DatabaseOpenWidget::enterKey(const QString& pw, const QString& keyFile)
void DatabaseOpenWidget::openDatabase() void DatabaseOpenWidget::openDatabase()
{ {
KeePass2Reader reader; KeePass2Reader reader;
CompositeKey masterKey; CompositeKey masterKey = databaseKey();
if (masterKey.isEmpty()) {
if (m_ui->checkPassword->isChecked()) {
masterKey.addKey(PasswordKey(m_ui->editPassword->text()));
}
QHash<QString, QVariant> lastKeyFiles = config()->get("LastKeyFiles").toHash();
if (m_ui->checkKeyFile->isChecked()) {
FileKey key;
QString keyFilename = m_ui->comboKeyFile->currentText();
QString errorMsg;
if (!key.load(keyFilename, &errorMsg)) {
QMessageBox::warning(this, tr("Error"), tr("Can't open key file:\n%1").arg(errorMsg));
return; return;
} }
masterKey.addKey(key);
lastKeyFiles[m_filename] = keyFilename;
}
else {
lastKeyFiles.remove(m_filename);
}
config()->set("LastKeyFiles", lastKeyFiles);
QFile file(m_filename); QFile file(m_filename);
if (!file.open(QIODevice::ReadOnly)) { if (!file.open(QIODevice::ReadOnly)) {
@ -141,6 +121,36 @@ void DatabaseOpenWidget::openDatabase()
} }
} }
CompositeKey DatabaseOpenWidget::databaseKey()
{
CompositeKey masterKey;
if (m_ui->checkPassword->isChecked()) {
masterKey.addKey(PasswordKey(m_ui->editPassword->text()));
}
QHash<QString, QVariant> lastKeyFiles = config()->get("LastKeyFiles").toHash();
if (m_ui->checkKeyFile->isChecked()) {
FileKey key;
QString keyFilename = m_ui->comboKeyFile->currentText();
QString errorMsg;
if (!key.load(keyFilename, &errorMsg)) {
QMessageBox::warning(this, tr("Error"), tr("Can't open key file:\n%1").arg(errorMsg));
return CompositeKey();
}
masterKey.addKey(key);
lastKeyFiles[m_filename] = keyFilename;
}
else {
lastKeyFiles.remove(m_filename);
}
config()->set("LastKeyFiles", lastKeyFiles);
return masterKey;
}
void DatabaseOpenWidget::reject() void DatabaseOpenWidget::reject()
{ {
Q_EMIT editFinished(false); Q_EMIT editFinished(false);

View File

@ -21,6 +21,7 @@
#include <QtCore/QScopedPointer> #include <QtCore/QScopedPointer>
#include "gui/DialogyWidget.h" #include "gui/DialogyWidget.h"
#include "keys/CompositeKey.h"
class Database; class Database;
class QFile; class QFile;
@ -43,6 +44,9 @@ public:
Q_SIGNALS: Q_SIGNALS:
void editFinished(bool accepted); void editFinished(bool accepted);
protected:
CompositeKey databaseKey();
protected Q_SLOTS: protected Q_SLOTS:
virtual void openDatabase(); virtual void openDatabase();
void reject(); void reject();

View File

@ -297,6 +297,7 @@ void DatabaseTabWidget::saveDatabaseAs(Database* db)
dbStruct.filePath = fileInfo.absoluteFilePath(); dbStruct.filePath = fileInfo.absoluteFilePath();
dbStruct.canonicalFilePath = fileInfo.canonicalFilePath(); dbStruct.canonicalFilePath = fileInfo.canonicalFilePath();
dbStruct.fileName = fileInfo.fileName(); dbStruct.fileName = fileInfo.fileName();
dbStruct.dbWidget->updateFilename(dbStruct.filePath);
updateTabName(db); updateTabName(db);
updateLastDatabases(dbStruct.filePath); updateLastDatabases(dbStruct.filePath);
} }
@ -391,20 +392,35 @@ void DatabaseTabWidget::updateTabName(Database* db)
tabName = QString("%1 [%2]").arg(db->metadata()->name(), tr("New database")); tabName = QString("%1 [%2]").arg(db->metadata()->name(), tr("New database"));
} }
} }
if (dbStruct.dbWidget->currentMode() == DatabaseWidget::LockedMode) {
tabName.append(QString(" [%1]").arg(tr("locked")));
}
if (dbStruct.modified) { if (dbStruct.modified) {
tabName.append("*"); tabName.append("*");
} }
setTabText(index, tabName); setTabText(index, tabName);
Q_EMIT tabNameChanged(); Q_EMIT tabNameChanged();
} }
void DatabaseTabWidget::updateTabNameFromSender() void DatabaseTabWidget::updateTabNameFromDbSender()
{ {
Q_ASSERT(qobject_cast<Database*>(sender())); Q_ASSERT(qobject_cast<Database*>(sender()));
updateTabName(static_cast<Database*>(sender())); updateTabName(static_cast<Database*>(sender()));
} }
void DatabaseTabWidget::updateTabNameFromDbWidgetSender()
{
Q_ASSERT(qobject_cast<DatabaseWidget*>(sender()));
Q_ASSERT(databaseFromDatabaseWidget(qobject_cast<DatabaseWidget*>(sender())));
DatabaseWidget* dbWidget = static_cast<DatabaseWidget*>(sender());
updateTabName(databaseFromDatabaseWidget(dbWidget));
}
int DatabaseTabWidget::databaseIndex(Database* db) int DatabaseTabWidget::databaseIndex(Database* db)
{ {
QWidget* dbWidget = m_dbList.value(db).dbWidget; QWidget* dbWidget = m_dbList.value(db).dbWidget;
@ -466,6 +482,7 @@ void DatabaseTabWidget::insertDatabase(Database* db, const DatabaseManagerStruct
connectDatabase(db); connectDatabase(db);
connect(dbStruct.dbWidget, SIGNAL(closeRequest()), SLOT(closeDatabaseFromSender())); connect(dbStruct.dbWidget, SIGNAL(closeRequest()), SLOT(closeDatabaseFromSender()));
connect(dbStruct.dbWidget, SIGNAL(databaseChanged(Database*)), SLOT(changeDatabase(Database*))); connect(dbStruct.dbWidget, SIGNAL(databaseChanged(Database*)), SLOT(changeDatabase(Database*)));
connect(dbStruct.dbWidget, SIGNAL(unlockedDatabase()), SLOT(updateTabNameFromDbWidgetSender()));
} }
DatabaseWidget* DatabaseTabWidget::currentDatabaseWidget() DatabaseWidget* DatabaseTabWidget::currentDatabaseWidget()
@ -479,6 +496,37 @@ DatabaseWidget* DatabaseTabWidget::currentDatabaseWidget()
} }
} }
bool DatabaseTabWidget::hasLockableDatabases()
{
QHashIterator<Database*, DatabaseManagerStruct> i(m_dbList);
while (i.hasNext()) {
i.next();
DatabaseWidget::Mode mode = i.value().dbWidget->currentMode();
if ((mode == DatabaseWidget::ViewMode || mode == DatabaseWidget::EditMode)
&& i.value().dbWidget->dbHasKey()) {
return true;
}
}
return false;
}
void DatabaseTabWidget::lockDatabases()
{
QHashIterator<Database*, DatabaseManagerStruct> i(m_dbList);
while (i.hasNext()) {
i.next();
DatabaseWidget::Mode mode = i.value().dbWidget->currentMode();
if ((mode == DatabaseWidget::ViewMode || mode == DatabaseWidget::EditMode)
&& i.value().dbWidget->dbHasKey()) {
i.value().dbWidget->lock();
updateTabName(i.key());
}
}
}
void DatabaseTabWidget::modified() void DatabaseTabWidget::modified()
{ {
Q_ASSERT(qobject_cast<Database*>(sender())); Q_ASSERT(qobject_cast<Database*>(sender()));
@ -535,7 +583,7 @@ void DatabaseTabWidget::connectDatabase(Database* newDb, Database* oldDb)
oldDb->disconnect(this); oldDb->disconnect(this);
} }
connect(newDb, SIGNAL(nameTextChanged()), SLOT(updateTabNameFromSender())); connect(newDb, SIGNAL(nameTextChanged()), SLOT(updateTabNameFromDbSender()));
connect(newDb, SIGNAL(modified()), SLOT(modified())); connect(newDb, SIGNAL(modified()), SLOT(modified()));
newDb->setEmitModified(true); newDb->setEmitModified(true);
} }

View File

@ -53,6 +53,7 @@ public:
void openDatabase(const QString& fileName, const QString& pw = QString(), void openDatabase(const QString& fileName, const QString& pw = QString(),
const QString& keyFile = QString()); const QString& keyFile = QString());
DatabaseWidget* currentDatabaseWidget(); DatabaseWidget* currentDatabaseWidget();
bool hasLockableDatabases();
static const int LastDatabasesCount; static const int LastDatabasesCount;
@ -69,13 +70,15 @@ public Q_SLOTS:
void changeDatabaseSettings(); void changeDatabaseSettings();
bool readOnly(int index = -1); bool readOnly(int index = -1);
void performGlobalAutoType(); void performGlobalAutoType();
void lockDatabases();
Q_SIGNALS: Q_SIGNALS:
void tabNameChanged(); void tabNameChanged();
private Q_SLOTS: private Q_SLOTS:
void updateTabName(Database* db); void updateTabName(Database* db);
void updateTabNameFromSender(); void updateTabNameFromDbSender();
void updateTabNameFromDbWidgetSender();
void modified(); void modified();
void toggleTabbar(); void toggleTabbar();
void changeDatabase(Database* newDb); void changeDatabase(Database* newDb);

View File

@ -36,6 +36,7 @@
#include "gui/DatabaseOpenWidget.h" #include "gui/DatabaseOpenWidget.h"
#include "gui/DatabaseSettingsWidget.h" #include "gui/DatabaseSettingsWidget.h"
#include "gui/KeePass1OpenWidget.h" #include "gui/KeePass1OpenWidget.h"
#include "gui/UnlockDatabaseWidget.h"
#include "gui/entry/EditEntryWidget.h" #include "gui/entry/EditEntryWidget.h"
#include "gui/entry/EntryView.h" #include "gui/entry/EntryView.h"
#include "gui/group/EditGroupWidget.h" #include "gui/group/EditGroupWidget.h"
@ -121,6 +122,8 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
m_databaseOpenWidget->setObjectName("databaseOpenWidget"); m_databaseOpenWidget->setObjectName("databaseOpenWidget");
m_keepass1OpenWidget = new KeePass1OpenWidget(); m_keepass1OpenWidget = new KeePass1OpenWidget();
m_keepass1OpenWidget->setObjectName("keepass1OpenWidget"); m_keepass1OpenWidget->setObjectName("keepass1OpenWidget");
m_unlockDatabaseWidget = new UnlockDatabaseWidget();
m_unlockDatabaseWidget->setObjectName("unlockDatabaseWidget");
addWidget(m_mainWidget); addWidget(m_mainWidget);
addWidget(m_editEntryWidget); addWidget(m_editEntryWidget);
addWidget(m_editGroupWidget); addWidget(m_editGroupWidget);
@ -129,6 +132,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
addWidget(m_historyEditEntryWidget); addWidget(m_historyEditEntryWidget);
addWidget(m_databaseOpenWidget); addWidget(m_databaseOpenWidget);
addWidget(m_keepass1OpenWidget); addWidget(m_keepass1OpenWidget);
addWidget(m_unlockDatabaseWidget);
connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(clearLastGroup(Group*))); connect(m_groupView, SIGNAL(groupChanged(Group*)), this, SLOT(clearLastGroup(Group*)));
connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged())); connect(m_groupView, SIGNAL(groupChanged(Group*)), SIGNAL(groupChanged()));
@ -143,6 +147,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
connect(m_databaseSettingsWidget, SIGNAL(editFinished(bool)), SLOT(switchToView(bool))); connect(m_databaseSettingsWidget, SIGNAL(editFinished(bool)), SLOT(switchToView(bool)));
connect(m_databaseOpenWidget, SIGNAL(editFinished(bool)), SLOT(openDatabase(bool))); connect(m_databaseOpenWidget, SIGNAL(editFinished(bool)), SLOT(openDatabase(bool)));
connect(m_keepass1OpenWidget, SIGNAL(editFinished(bool)), SLOT(openDatabase(bool))); connect(m_keepass1OpenWidget, SIGNAL(editFinished(bool)), SLOT(openDatabase(bool)));
connect(m_unlockDatabaseWidget, SIGNAL(editFinished(bool)), SLOT(unlockDatabase(bool)));
connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged())); connect(this, SIGNAL(currentChanged(int)), this, SLOT(emitCurrentModeChanged()));
connect(m_searchUi->searchEdit, SIGNAL(textChanged(QString)), this, SLOT(startSearchTimer())); connect(m_searchUi->searchEdit, SIGNAL(textChanged(QString)), this, SLOT(startSearchTimer()));
connect(m_searchUi->caseSensitiveCheckBox, SIGNAL(toggled(bool)), this, SLOT(startSearch())); connect(m_searchUi->caseSensitiveCheckBox, SIGNAL(toggled(bool)), this, SLOT(startSearch()));
@ -151,7 +156,7 @@ DatabaseWidget::DatabaseWidget(Database* db, QWidget* parent)
connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(search())); connect(m_searchTimer, SIGNAL(timeout()), this, SLOT(search()));
connect(closeAction, SIGNAL(triggered()), this, SLOT(closeSearch())); connect(closeAction, SIGNAL(triggered()), this, SLOT(closeSearch()));
setCurrentIndex(0); setCurrentWidget(m_mainWidget);
} }
DatabaseWidget::~DatabaseWidget() DatabaseWidget::~DatabaseWidget()
@ -160,22 +165,17 @@ DatabaseWidget::~DatabaseWidget()
DatabaseWidget::Mode DatabaseWidget::currentMode() DatabaseWidget::Mode DatabaseWidget::currentMode()
{ {
switch (currentIndex()) { if (currentWidget() == Q_NULLPTR) {
case -1:
return DatabaseWidget::None; return DatabaseWidget::None;
case 0: }
else if (currentWidget() == m_mainWidget) {
return DatabaseWidget::ViewMode; return DatabaseWidget::ViewMode;
case 1: // entry edit }
case 2: // group edit else if (currentWidget() == m_unlockDatabaseWidget) {
case 3: // change master key return DatabaseWidget::LockedMode;
case 4: // database settings }
case 5: // entry history else {
case 6: // open database
case 7: // keepass 1 import
return DatabaseWidget::EditMode; return DatabaseWidget::EditMode;
default:
Q_ASSERT(false);
return DatabaseWidget::None;
} }
} }
@ -347,12 +347,20 @@ int DatabaseWidget::addWidget(QWidget* w)
} }
void DatabaseWidget::setCurrentIndex(int index) void DatabaseWidget::setCurrentIndex(int index)
{
// use setCurrentWidget() instead
// index is not reliable
Q_UNUSED(index);
Q_ASSERT(false);
}
void DatabaseWidget::setCurrentWidget(QWidget* widget)
{ {
if (currentWidget()) { if (currentWidget()) {
currentWidget()->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); currentWidget()->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
} }
QStackedWidget::setCurrentIndex(index); QStackedWidget::setCurrentWidget(widget);
if (currentWidget()) { if (currentWidget()) {
currentWidget()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); currentWidget()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
@ -390,18 +398,18 @@ void DatabaseWidget::switchToView(bool accepted)
m_newParent = Q_NULLPTR; m_newParent = Q_NULLPTR;
} }
setCurrentIndex(0); setCurrentWidget(m_mainWidget);
} }
void DatabaseWidget::switchToHistoryView(Entry* entry) void DatabaseWidget::switchToHistoryView(Entry* entry)
{ {
m_historyEditEntryWidget->loadEntry(entry, false, true, "", m_db); m_historyEditEntryWidget->loadEntry(entry, false, true, "", m_db);
setCurrentIndex(5); setCurrentWidget(m_historyEditEntryWidget);
} }
void DatabaseWidget::switchBackToEntryEdit() void DatabaseWidget::switchBackToEntryEdit()
{ {
setCurrentIndex(1); setCurrentWidget(m_editEntryWidget);
} }
void DatabaseWidget::switchToEntryEdit(Entry* entry) void DatabaseWidget::switchToEntryEdit(Entry* entry)
@ -419,13 +427,13 @@ void DatabaseWidget::switchToEntryEdit(Entry* entry, bool create)
Q_ASSERT(group); Q_ASSERT(group);
m_editEntryWidget->loadEntry(entry, create, false, group->name(), m_db); m_editEntryWidget->loadEntry(entry, create, false, group->name(), m_db);
setCurrentIndex(1); setCurrentWidget(m_editEntryWidget);
} }
void DatabaseWidget::switchToGroupEdit(Group* group, bool create) void DatabaseWidget::switchToGroupEdit(Group* group, bool create)
{ {
m_editGroupWidget->loadGroup(group, create, m_db); m_editGroupWidget->loadGroup(group, create, m_db);
setCurrentIndex(2); setCurrentWidget(m_editGroupWidget);
} }
void DatabaseWidget::updateMasterKey(bool accepted) void DatabaseWidget::updateMasterKey(bool accepted)
@ -440,7 +448,7 @@ void DatabaseWidget::updateMasterKey(bool accepted)
return; return;
} }
setCurrentIndex(0); setCurrentWidget(m_mainWidget);
} }
void DatabaseWidget::openDatabase(bool accepted) void DatabaseWidget::openDatabase(bool accepted)
@ -451,7 +459,7 @@ void DatabaseWidget::openDatabase(bool accepted)
m_groupView->changeDatabase(m_db); m_groupView->changeDatabase(m_db);
Q_EMIT databaseChanged(m_db); Q_EMIT databaseChanged(m_db);
delete oldDb; delete oldDb;
setCurrentIndex(0); setCurrentWidget(m_mainWidget);
// We won't need those anymore and KeePass1OpenWidget closes // We won't need those anymore and KeePass1OpenWidget closes
// the file in its dtor. // the file in its dtor.
@ -468,6 +476,15 @@ void DatabaseWidget::openDatabase(bool accepted)
} }
} }
void DatabaseWidget::unlockDatabase(bool accepted)
{
// cancel button is disabled
Q_ASSERT(accepted);
setCurrentWidget(widgetBeforeLock);
Q_EMIT unlockedDatabase();
}
void DatabaseWidget::switchToEntryEdit() void DatabaseWidget::switchToEntryEdit()
{ {
switchToEntryEdit(m_entryView->currentEntry(), false); switchToEntryEdit(m_entryView->currentEntry(), false);
@ -481,32 +498,35 @@ void DatabaseWidget::switchToGroupEdit()
void DatabaseWidget::switchToMasterKeyChange() void DatabaseWidget::switchToMasterKeyChange()
{ {
m_changeMasterKeyWidget->clearForms(); m_changeMasterKeyWidget->clearForms();
setCurrentIndex(3); setCurrentWidget(m_changeMasterKeyWidget);
} }
void DatabaseWidget::switchToDatabaseSettings() void DatabaseWidget::switchToDatabaseSettings()
{ {
m_databaseSettingsWidget->load(m_db); m_databaseSettingsWidget->load(m_db);
setCurrentIndex(4); setCurrentWidget(m_databaseSettingsWidget);
} }
void DatabaseWidget::switchToOpenDatabase(const QString& fileName) void DatabaseWidget::switchToOpenDatabase(const QString& fileName)
{ {
updateFilename(fileName);
m_databaseOpenWidget->load(fileName); m_databaseOpenWidget->load(fileName);
setCurrentIndex(6); setCurrentWidget(m_databaseOpenWidget);
} }
void DatabaseWidget::switchToOpenDatabase(const QString& fileName, const QString& password, void DatabaseWidget::switchToOpenDatabase(const QString& fileName, const QString& password,
const QString& keyFile) const QString& keyFile)
{ {
updateFilename(fileName);
switchToOpenDatabase(fileName); switchToOpenDatabase(fileName);
m_databaseOpenWidget->enterKey(password, keyFile); m_databaseOpenWidget->enterKey(password, keyFile);
} }
void DatabaseWidget::switchToImportKeepass1(const QString& fileName) void DatabaseWidget::switchToImportKeepass1(const QString& fileName)
{ {
updateFilename(fileName);
m_keepass1OpenWidget->load(fileName); m_keepass1OpenWidget->load(fileName);
setCurrentIndex(7); setCurrentWidget(m_keepass1OpenWidget);
} }
void DatabaseWidget::toggleSearch() void DatabaseWidget::toggleSearch()
@ -641,3 +661,17 @@ void DatabaseWidget::clearLastGroup(Group* group)
m_searchWidget->hide(); m_searchWidget->hide();
} }
} }
void DatabaseWidget::lock()
{
Q_ASSERT(currentMode() != DatabaseWidget::LockedMode);
widgetBeforeLock = currentWidget();
m_unlockDatabaseWidget->load(m_filename, m_db);
setCurrentWidget(m_unlockDatabaseWidget);
}
void DatabaseWidget::updateFilename(const QString& fileName)
{
m_filename = fileName;
}

View File

@ -36,6 +36,7 @@ class GroupView;
class KeePass1OpenWidget; class KeePass1OpenWidget;
class QFile; class QFile;
class QMenu; class QMenu;
class UnlockDatabaseWidget;
namespace Ui { namespace Ui {
class SearchWidget; class SearchWidget;
@ -50,7 +51,8 @@ public:
{ {
None, None,
ViewMode, ViewMode,
EditMode EditMode,
LockedMode
}; };
explicit DatabaseWidget(Database* db, QWidget* parent = Q_NULLPTR); explicit DatabaseWidget(Database* db, QWidget* parent = Q_NULLPTR);
@ -63,7 +65,10 @@ public:
bool isInSearchMode(); bool isInSearchMode();
int addWidget(QWidget* w); int addWidget(QWidget* w);
void setCurrentIndex(int index); void setCurrentIndex(int index);
void setCurrentWidget(QWidget* widget);
DatabaseWidget::Mode currentMode(); DatabaseWidget::Mode currentMode();
void lock();
void updateFilename(const QString& filename);
Q_SIGNALS: Q_SIGNALS:
void closeRequest(); void closeRequest();
@ -73,6 +78,7 @@ Q_SIGNALS:
void databaseChanged(Database* newDb); void databaseChanged(Database* newDb);
void groupContextMenuRequested(const QPoint& globalPos); void groupContextMenuRequested(const QPoint& globalPos);
void entryContextMenuRequested(const QPoint& globalPos); void entryContextMenuRequested(const QPoint& globalPos);
void unlockedDatabase();
public Q_SLOTS: public Q_SLOTS:
void createEntry(); void createEntry();
@ -104,6 +110,7 @@ private Q_SLOTS:
void switchToGroupEdit(Group* entry, bool create); void switchToGroupEdit(Group* entry, bool create);
void updateMasterKey(bool accepted); void updateMasterKey(bool accepted);
void openDatabase(bool accepted); void openDatabase(bool accepted);
void unlockDatabase(bool accepted);
void emitCurrentModeChanged(); void emitCurrentModeChanged();
void clearLastGroup(Group* group); void clearLastGroup(Group* group);
void search(); void search();
@ -124,6 +131,7 @@ private:
DatabaseSettingsWidget* m_databaseSettingsWidget; DatabaseSettingsWidget* m_databaseSettingsWidget;
DatabaseOpenWidget* m_databaseOpenWidget; DatabaseOpenWidget* m_databaseOpenWidget;
KeePass1OpenWidget* m_keepass1OpenWidget; KeePass1OpenWidget* m_keepass1OpenWidget;
UnlockDatabaseWidget* m_unlockDatabaseWidget;
GroupView* m_groupView; GroupView* m_groupView;
EntryView* m_entryView; EntryView* m_entryView;
Group* m_newGroup; Group* m_newGroup;
@ -131,6 +139,8 @@ private:
Group* m_newParent; Group* m_newParent;
Group* m_lastGroup; Group* m_lastGroup;
QTimer* m_searchTimer; QTimer* m_searchTimer;
QWidget* widgetBeforeLock;
QString m_filename;
}; };
#endif // KEEPASSX_DATABASEWIDGET_H #endif // KEEPASSX_DATABASEWIDGET_H

View File

@ -29,7 +29,7 @@
KeePass1OpenWidget::KeePass1OpenWidget(QWidget* parent) KeePass1OpenWidget::KeePass1OpenWidget(QWidget* parent)
: DatabaseOpenWidget(parent) : DatabaseOpenWidget(parent)
{ {
setWindowTitle(tr("Import KeePass1 database")); m_ui->labelHeadline->setText(tr("Import KeePass1 database"));
} }
void KeePass1OpenWidget::openDatabase() void KeePass1OpenWidget::openDatabase()

View File

@ -63,6 +63,7 @@ MainWindow::MainWindow()
setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S); setShortcut(m_ui->actionDatabaseSave, QKeySequence::Save, Qt::CTRL + Qt::Key_S);
setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs); setShortcut(m_ui->actionDatabaseSaveAs, QKeySequence::SaveAs);
setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W); setShortcut(m_ui->actionDatabaseClose, QKeySequence::Close, Qt::CTRL + Qt::Key_W);
m_ui->actionLockDatabases->setShortcut(Qt::CTRL + Qt::Key_L);
setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q); setShortcut(m_ui->actionQuit, QKeySequence::Quit, Qt::CTRL + Qt::Key_Q);
setShortcut(m_ui->actionSearch, QKeySequence::Find, Qt::CTRL + Qt::Key_F); setShortcut(m_ui->actionSearch, QKeySequence::Find, Qt::CTRL + Qt::Key_F);
m_ui->actionEntryNew->setShortcut(Qt::CTRL + Qt::Key_N); m_ui->actionEntryNew->setShortcut(Qt::CTRL + Qt::Key_N);
@ -85,6 +86,7 @@ MainWindow::MainWindow()
m_ui->actionDatabaseClose->setIcon(filePath()->icon("actions", "document-close")); m_ui->actionDatabaseClose->setIcon(filePath()->icon("actions", "document-close"));
m_ui->actionChangeDatabaseSettings->setIcon(filePath()->icon("actions", "document-edit")); m_ui->actionChangeDatabaseSettings->setIcon(filePath()->icon("actions", "document-edit"));
m_ui->actionChangeMasterKey->setIcon(filePath()->icon("actions", "database-change-key", false)); m_ui->actionChangeMasterKey->setIcon(filePath()->icon("actions", "database-change-key", false));
m_ui->actionLockDatabases->setIcon(filePath()->icon("actions", "document-encrypt", false));
m_ui->actionQuit->setIcon(filePath()->icon("actions", "application-exit")); m_ui->actionQuit->setIcon(filePath()->icon("actions", "application-exit"));
m_ui->actionEntryNew->setIcon(filePath()->icon("actions", "entry-new", false)); m_ui->actionEntryNew->setIcon(filePath()->icon("actions", "entry-new", false));
@ -140,6 +142,8 @@ MainWindow::MainWindow()
SLOT(changeDatabaseSettings())); SLOT(changeDatabaseSettings()));
connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget, connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(importKeePass1Database())); SLOT(importKeePass1Database()));
connect(m_ui->actionLockDatabases, SIGNAL(triggered()), m_ui->tabWidget,
SLOT(lockDatabases()));
connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(close())); connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(close()));
m_actionMultiplexer.connect(m_ui->actionEntryNew, SIGNAL(triggered()), m_actionMultiplexer.connect(m_ui->actionEntryNew, SIGNAL(triggered()),
@ -246,6 +250,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
break; break;
} }
case DatabaseWidget::EditMode: case DatabaseWidget::EditMode:
case DatabaseWidget::LockedMode:
Q_FOREACH (QAction* action, m_ui->menuEntries->actions()) { Q_FOREACH (QAction* action, m_ui->menuEntries->actions()) {
action->setEnabled(false); action->setEnabled(false);
} }
@ -290,6 +295,8 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionImportKeePass1->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->actionImportKeePass1->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionLockDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
} }
void MainWindow::updateWindowTitle() void MainWindow::updateWindowTitle()

View File

@ -94,6 +94,7 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionImportKeePass1"/> <addaction name="actionImportKeePass1"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionLockDatabases"/>
<addaction name="actionQuit"/> <addaction name="actionQuit"/>
</widget> </widget>
<widget class="QMenu" name="menuHelp"> <widget class="QMenu" name="menuHelp">
@ -328,6 +329,14 @@
<string>Open URL</string> <string>Open URL</string>
</property> </property>
</action> </action>
<action name="actionLockDatabases">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Lock databases</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2012 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 "UnlockDatabaseWidget.h"
#include <QtGui/QMessageBox>
#include "ui_DatabaseOpenWidget.h"
#include "core/Database.h"
UnlockDatabaseWidget::UnlockDatabaseWidget(QWidget* parent)
: DatabaseOpenWidget(parent)
{
m_ui->labelHeadline->setText(tr("Unlock database"));
m_ui->buttonBox->removeButton(m_ui->buttonBox->button(QDialogButtonBox::Cancel));
connect(this, SIGNAL(editFinished(bool)), SLOT(clearForms()));
}
void UnlockDatabaseWidget::load(const QString& filename, Database* db)
{
Q_ASSERT(db);
DatabaseOpenWidget::load(filename);
m_db = db;
}
void UnlockDatabaseWidget::openDatabase()
{
CompositeKey masterKey = databaseKey();
if (masterKey.isEmpty()) {
return;
}
if (m_db->verifyKey(masterKey)) {
Q_EMIT editFinished(true);
}
else {
QMessageBox::warning(this, tr("Error"), tr("Wrong key."));
m_ui->editPassword->clear();
}
}
void UnlockDatabaseWidget::clearForms()
{
m_ui->editPassword->clear();
m_ui->comboKeyFile->clear();
m_ui->checkPassword->setChecked(false);
m_ui->checkKeyFile->setChecked(false);
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2012 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 "gui/DatabaseOpenWidget.h"
class UnlockDatabaseWidget : public DatabaseOpenWidget
{
Q_OBJECT
public:
explicit UnlockDatabaseWidget(QWidget* parent = Q_NULLPTR);
void load(const QString& filename, Database* db);
protected:
void openDatabase() Q_DECL_OVERRIDE;
private Q_SLOTS:
void clearForms();
};

View File

@ -336,6 +336,24 @@ void TestGui::testKeePass1Import()
QCOMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("basic [New database]*")); QCOMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("basic [New database]*"));
} }
void TestGui::testDatabaseLocking()
{
triggerAction("actionLockDatabases");
QCOMPARE(m_tabWidget->tabText(0), QString("Save [locked]"));
QCOMPARE(m_tabWidget->tabText(1), QString("basic [New database] [locked]*"));
QWidget* dbWidget = m_tabWidget->currentDatabaseWidget();
QWidget* unlockDatabaseWidget = dbWidget->findChild<QWidget*>("unlockDatabaseWidget");
QWidget* editPassword = unlockDatabaseWidget->findChild<QLineEdit*>("editPassword");
QVERIFY(editPassword);
QTest::keyClicks(editPassword, "masterpw");
QTest::keyClick(editPassword, Qt::Key_Enter);
QCOMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("basic [New database]*"));
}
void TestGui::cleanupTestCase() void TestGui::cleanupTestCase()
{ {
delete m_mainWindow; delete m_mainWindow;

View File

@ -45,6 +45,7 @@ private Q_SLOTS:
void testSave(); void testSave();
void testDatabaseSettings(); void testDatabaseSettings();
void testKeePass1Import(); void testKeePass1Import();
void testDatabaseLocking();
void cleanupTestCase(); void cleanupTestCase();
private: private: