diff options
Diffstat (limited to 'src/gui/DatabaseWidget.cpp')
-rw-r--r-- | src/gui/DatabaseWidget.cpp | 423 |
1 files changed, 347 insertions, 76 deletions
diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 990cf4e34..61f2b2163 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -25,21 +25,23 @@ #include <QFile> #include <QHBoxLayout> #include <QHeaderView> +#include <QHostInfo> #include <QKeyEvent> #include <QLabel> #include <QLineEdit> #include <QProcess> #include <QSplitter> +#include <QTextEdit> #include "autotype/AutoType.h" #include "core/Config.h" #include "core/Database.h" #include "core/EntrySearcher.h" -#include "core/FilePath.h" #include "core/FileWatcher.h" #include "core/Group.h" #include "core/Merger.h" #include "core/Metadata.h" +#include "core/Resources.h" #include "core/Tools.h" #include "format/KeePass2Reader.h" #include "gui/Clipboard.h" @@ -49,6 +51,7 @@ #include "gui/EntryPreviewWidget.h" #include "gui/FileDialog.h" #include "gui/KeePass1OpenWidget.h" +#include "gui/MainWindow.h" #include "gui/MessageBox.h" #include "gui/OpVaultOpenWidget.h" #include "gui/TotpDialog.h" @@ -59,6 +62,7 @@ #include "gui/entry/EntryView.h" #include "gui/group/EditGroupWidget.h" #include "gui/group/GroupView.h" +#include "gui/reports/ReportsDialog.h" #include "keeshare/KeeShare.h" #include "touchid/TouchID.h" @@ -88,6 +92,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) , m_editEntryWidget(new EditEntryWidget(this)) , m_editGroupWidget(new EditGroupWidget(this)) , m_historyEditEntryWidget(new EditEntryWidget(this)) + , m_reportsDialog(new ReportsDialog(this)) , m_databaseSettingDialog(new DatabaseSettingsDialog(this)) , m_databaseOpenWidget(new DatabaseOpenWidget(this)) , m_keepass1OpenWidget(new KeePass1OpenWidget(this)) @@ -165,6 +170,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) m_editEntryWidget->setObjectName("editEntryWidget"); m_editGroupWidget->setObjectName("editGroupWidget"); m_csvImportWizard->setObjectName("csvImportWizard"); + m_reportsDialog->setObjectName("reportsDialog"); m_databaseSettingDialog->setObjectName("databaseSettingsDialog"); m_databaseOpenWidget->setObjectName("databaseOpenWidget"); m_keepass1OpenWidget->setObjectName("keepass1OpenWidget"); @@ -173,6 +179,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) addChildWidget(m_mainWidget); addChildWidget(m_editEntryWidget); addChildWidget(m_editGroupWidget); + addChildWidget(m_reportsDialog); addChildWidget(m_databaseSettingDialog); addChildWidget(m_historyEditEntryWidget); addChildWidget(m_databaseOpenWidget); @@ -187,8 +194,9 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) connect(m_previewView, SIGNAL(errorOccurred(QString)), SLOT(showErrorMessage(QString))); connect(m_previewView, SIGNAL(entryUrlActivated(Entry*)), SLOT(openUrlForEntry(Entry*))); connect(m_entryView, SIGNAL(viewStateChanged()), SIGNAL(entryViewStateChanged())); - connect(m_groupView, SIGNAL(groupSelectionChanged(Group*)), SLOT(onGroupChanged(Group*))); - connect(m_groupView, SIGNAL(groupSelectionChanged(Group*)), SIGNAL(groupChanged())); + connect(m_groupView, SIGNAL(groupSelectionChanged()), SLOT(onGroupChanged())); + connect(m_groupView, SIGNAL(groupSelectionChanged()), SIGNAL(groupChanged())); + connect(m_groupView, &GroupView::groupFocused, this, [this] { m_previewView->setGroup(currentGroup()); }); connect(m_entryView, SIGNAL(entryActivated(Entry*,EntryModel::ModelColumn)), SLOT(entryActivationSignalReceived(Entry*,EntryModel::ModelColumn))); connect(m_entryView, SIGNAL(entrySelectionChanged(Entry*)), SLOT(onEntryChanged(Entry*))); @@ -196,6 +204,7 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) connect(m_editEntryWidget, SIGNAL(historyEntryActivated(Entry*)), SLOT(switchToHistoryView(Entry*))); connect(m_historyEditEntryWidget, SIGNAL(editFinished(bool)), SLOT(switchBackToEntryEdit())); connect(m_editGroupWidget, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); + connect(m_reportsDialog, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); connect(m_databaseSettingDialog, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); connect(m_databaseOpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); connect(m_keepass1OpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); @@ -209,12 +218,12 @@ DatabaseWidget::DatabaseWidget(QSharedPointer<Database> db, QWidget* parent) m_blockAutoSave = false; m_EntrySearcher = new EntrySearcher(false); - m_searchLimitGroup = config()->get("SearchLimitGroup", false).toBool(); + m_searchLimitGroup = config()->get(Config::SearchLimitGroup).toBool(); #ifdef WITH_XC_SSHAGENT - if (config()->get("SSHAgent", false).toBool()) { - connect(this, SIGNAL(databaseLocked()), SSHAgent::instance(), SLOT(databaseModeChanged())); - connect(this, SIGNAL(databaseUnlocked()), SSHAgent::instance(), SLOT(databaseModeChanged())); + if (sshAgent()->isEnabled()) { + connect(this, SIGNAL(databaseLockRequested()), sshAgent(), SLOT(databaseLocked())); + connect(this, SIGNAL(databaseUnlocked()), sshAgent(), SLOT(databaseUnlocked())); } #endif @@ -249,15 +258,15 @@ QSharedPointer<Database> DatabaseWidget::database() const DatabaseWidget::Mode DatabaseWidget::currentMode() const { if (currentWidget() == nullptr) { - return DatabaseWidget::Mode::None; + return Mode::None; } else if (currentWidget() == m_mainWidget) { - return DatabaseWidget::Mode::ViewMode; + return Mode::ViewMode; } else if (currentWidget() == m_databaseOpenWidget || currentWidget() == m_keepass1OpenWidget) { - return DatabaseWidget::Mode::LockedMode; + return Mode::LockedMode; } else if (currentWidget() == m_csvImportWizard) { - return DatabaseWidget::Mode::ImportMode; + return Mode::ImportMode; } else { - return DatabaseWidget::Mode::EditMode; + return Mode::EditMode; } } @@ -266,11 +275,26 @@ bool DatabaseWidget::isLocked() const return currentMode() == Mode::LockedMode; } +bool DatabaseWidget::isSaving() const +{ + return m_db->isSaving(); +} + +bool DatabaseWidget::isSorted() const +{ + return m_entryView->isSorted(); +} + bool DatabaseWidget::isSearchActive() const { return m_entryView->inSearchMode(); } +bool DatabaseWidget::isEntryViewActive() const +{ + return currentWidget() == m_mainWidget; +} + bool DatabaseWidget::isEntryEditActive() const { return currentWidget() == m_editEntryWidget; @@ -604,9 +628,45 @@ bool DatabaseWidget::confirmDeleteEntries(QList<Entry*> entries, bool permanent) } } -void DatabaseWidget::setFocus() +void DatabaseWidget::setFocus(Qt::FocusReason reason) { - m_entryView->setFocus(); + if (reason == Qt::BacktabFocusReason) { + m_previewView->setFocus(); + } else { + m_groupView->setFocus(); + } +} + +void DatabaseWidget::focusOnEntries() +{ + if (isEntryViewActive()) { + m_entryView->setFocus(); + } +} + +void DatabaseWidget::focusOnGroups() +{ + if (isEntryViewActive()) { + m_groupView->setFocus(); + } +} + +void DatabaseWidget::moveEntryUp() +{ + auto currentEntry = currentSelectedEntry(); + if (currentEntry) { + currentEntry->moveUp(); + m_entryView->setCurrentEntry(currentEntry); + } +} + +void DatabaseWidget::moveEntryDown() +{ + auto currentEntry = currentSelectedEntry(); + if (currentEntry) { + currentEntry->moveDown(); + m_entryView->setCurrentEntry(currentEntry); + } } void DatabaseWidget::copyTitle() @@ -627,6 +687,14 @@ void DatabaseWidget::copyUsername() void DatabaseWidget::copyPassword() { + // QTextEdit does not properly trap Ctrl+C copy shortcut + // if a text edit has focus pass the copy operation to it + auto textEdit = qobject_cast<QTextEdit*>(focusWidget()); + if (textEdit) { + textEdit->copy(); + return; + } + auto currentEntry = currentSelectedEntry(); if (currentEntry) { setClipboardTextAndMinimize(currentEntry->resolveMultiplePlaceholders(currentEntry->password())); @@ -670,15 +738,59 @@ void DatabaseWidget::showTotpKeyQrCode() void DatabaseWidget::setClipboardTextAndMinimize(const QString& text) { clipboard()->setText(text); - if (config()->get("HideWindowOnCopy").toBool()) { - if (config()->get("MinimizeOnCopy").toBool()) { - window()->showMinimized(); - } else if (config()->get("DropToBackgroundOnCopy").toBool()) { + if (config()->get(Config::HideWindowOnCopy).toBool()) { + if (config()->get(Config::MinimizeOnCopy).toBool()) { + getMainWindow()->minimizeOrHide(); + } else if (config()->get(Config::DropToBackgroundOnCopy).toBool()) { window()->lower(); } } } +#ifdef WITH_XC_SSHAGENT +void DatabaseWidget::addToAgent() +{ + Entry* currentEntry = m_entryView->currentEntry(); + Q_ASSERT(currentEntry); + if (!currentEntry) { + return; + } + + KeeAgentSettings settings; + if (!settings.fromEntry(currentEntry)) { + return; + } + + OpenSSHKey key; + if (settings.toOpenSSHKey(currentEntry, key, true)) { + SSHAgent::instance()->addIdentity(key, settings, database()->uuid()); + } else { + m_messageWidget->showMessage(key.errorString(), MessageWidget::Error); + } +} + +void DatabaseWidget::removeFromAgent() +{ + Entry* currentEntry = m_entryView->currentEntry(); + Q_ASSERT(currentEntry); + if (!currentEntry) { + return; + } + + KeeAgentSettings settings; + if (!settings.fromEntry(currentEntry)) { + return; + } + + OpenSSHKey key; + if (settings.toOpenSSHKey(currentEntry, key, false)) { + SSHAgent::instance()->removeIdentity(key); + } else { + m_messageWidget->showMessage(key.errorString(), MessageWidget::Error); + } +} +#endif + void DatabaseWidget::performAutoType() { auto currentEntry = currentSelectedEntry(); @@ -776,17 +888,19 @@ void DatabaseWidget::openUrlForEntry(Entry* entry) if (launch) { QProcess::startDetached(cmdString.mid(6)); - if (config()->get("MinimizeOnOpenUrl").toBool()) { - window()->showMinimized(); + if (config()->get(Config::MinimizeOnOpenUrl).toBool()) { + getMainWindow()->minimizeOrHide(); } } + } else if (cmdString.startsWith("kdbx://")) { + openDatabaseFromEntry(entry, false); } else { QUrl url = QUrl::fromUserInput(entry->resolveMultiplePlaceholders(entry->url())); if (!url.isEmpty()) { QDesktopServices::openUrl(url); - if (config()->get("MinimizeOnOpenUrl").toBool()) { - window()->showMinimized(); + if (config()->get(Config::MinimizeOnOpenUrl).toBool()) { + getMainWindow()->minimizeOrHide(); } } } @@ -861,6 +975,8 @@ int DatabaseWidget::addChildWidget(QWidget* w) void DatabaseWidget::switchToMainView(bool previousDialogAccepted) { + setCurrentWidget(m_mainWidget); + if (m_newGroup) { if (previousDialogAccepted) { m_newGroup->setParent(m_newParent); @@ -886,12 +1002,10 @@ void DatabaseWidget::switchToMainView(bool previousDialogAccepted) m_entryView->setFocus(); } - setCurrentWidget(m_mainWidget); - if (sender() == m_entryView || sender() == m_editEntryWidget) { onEntryChanged(m_entryView->currentEntry()); } else if (sender() == m_groupView || sender() == m_editGroupWidget) { - onGroupChanged(m_groupView->currentGroup()); + onGroupChanged(); } } @@ -966,8 +1080,8 @@ void DatabaseWidget::loadDatabase(bool accepted) processAutoOpen(); m_saveAttempts = 0; emit databaseUnlocked(); - if (config()->get("MinimizeAfterUnlock").toBool()) { - window()->showMinimized(); + if (config()->get(Config::MinimizeAfterUnlock).toBool()) { + getMainWindow()->minimizeOrHide(); } } else { if (m_databaseOpenWidget->database()) { @@ -1105,6 +1219,12 @@ void DatabaseWidget::entryActivationSignalReceived(Entry* entry, EntryModel::Mod } } +void DatabaseWidget::switchToDatabaseReports() +{ + m_reportsDialog->load(m_db); + setCurrentWidget(m_reportsDialog); +} + void DatabaseWidget::switchToDatabaseSettings() { m_databaseSettingDialog->load(m_db); @@ -1113,7 +1233,9 @@ void DatabaseWidget::switchToDatabaseSettings() void DatabaseWidget::switchToOpenDatabase() { - switchToOpenDatabase(m_db->filePath()); + if (currentWidget() != m_databaseOpenWidget || m_databaseOpenWidget->filename() != m_db->filePath()) { + switchToOpenDatabase(m_db->filePath()); + } } void DatabaseWidget::switchToOpenDatabase(const QString& filePath) @@ -1185,10 +1307,10 @@ void DatabaseWidget::sortGroupsDesc() m_groupView->sortGroups(true); } -void DatabaseWidget::switchToMasterKeyChange() +void DatabaseWidget::switchToDatabaseSecurity() { switchToDatabaseSettings(); - m_databaseSettingDialog->showMasterKeySettings(); + m_databaseSettingDialog->showDatabaseKeySettings(); } void DatabaseWidget::performUnlockDatabase(const QString& password, const QString& keyfile) @@ -1253,8 +1375,10 @@ void DatabaseWidget::setSearchLimitGroup(bool state) refreshSearch(); } -void DatabaseWidget::onGroupChanged(Group* group) +void DatabaseWidget::onGroupChanged() { + auto group = m_groupView->currentGroup(); + // Intercept group changes if in search mode if (isSearchActive() && m_searchLimitGroup) { search(m_lastSearchText); @@ -1279,7 +1403,7 @@ void DatabaseWidget::onGroupChanged(Group* group) void DatabaseWidget::onDatabaseModified() { - if (!m_blockAutoSave && config()->get("AutoSaveAfterEveryChange").toBool() && !m_db->isReadOnly()) { + if (!m_blockAutoSave && config()->get(Config::AutoSaveAfterEveryChange).toBool() && !m_db->isReadOnly()) { save(); } else { // Only block once, then reset @@ -1295,13 +1419,11 @@ QString DatabaseWidget::getCurrentSearch() void DatabaseWidget::endSearch() { if (isSearchActive()) { - emit listModeAboutToActivate(); - // Show the normal entry view of the current group + emit listModeAboutToActivate(); m_entryView->displayGroup(currentGroup()); - onGroupChanged(currentGroup()); - emit listModeActivated(); + m_entryView->setFirstEntryActive(); } m_searchingLabel->setVisible(false); @@ -1362,12 +1484,43 @@ void DatabaseWidget::showEvent(QShowEvent* event) event->accept(); } +bool DatabaseWidget::focusNextPrevChild(bool next) +{ + // [parent] <-> GroupView <-> EntryView <-> EntryPreview <-> [parent] + if (next) { + if (m_groupView->hasFocus()) { + m_entryView->setFocus(); + return true; + } else if (m_entryView->hasFocus()) { + m_previewView->setFocus(); + return true; + } + } else { + if (m_previewView->hasFocus()) { + m_entryView->setFocus(); + return true; + } else if (m_entryView->hasFocus()) { + m_groupView->setFocus(); + return true; + } + } + + // Defer to the parent widget to make a decision + return QStackedWidget::focusNextPrevChild(next); +} + bool DatabaseWidget::lock() { if (isLocked()) { return true; } + // Don't try to lock the database while saving, this will cause a deadlock + if (m_db->isSaving()) { + QTimer::singleShot(200, this, SLOT(lock())); + return false; + } + emit databaseLockRequested(); clipboard()->clearCopiedText(); @@ -1383,10 +1536,11 @@ bool DatabaseWidget::lock() } } - if (m_db->isModified()) { + if (m_db->isModified(true)) { bool saved = false; // Attempt to save on exit, but don't block locking if it fails - if (config()->get("AutoSaveOnExit").toBool() || config()->get("AutoSaveAfterEveryChange").toBool()) { + if (config()->get(Config::AutoSaveOnExit).toBool() + || config()->get(Config::AutoSaveAfterEveryChange).toBool()) { saved = save(); } @@ -1444,7 +1598,7 @@ void DatabaseWidget::reloadDatabaseFile() m_blockAutoSave = true; - if (!config()->get("AutoReloadOnChange").toBool()) { + if (!config()->get(Config::AutoReloadOnChange).toBool()) { // Ask if we want to reload the db auto result = MessageBox::question(this, tr("File has changed"), @@ -1466,7 +1620,7 @@ void DatabaseWidget::reloadDatabaseFile() QString error; auto db = QSharedPointer<Database>::create(m_db->filePath()); if (db->open(database()->key(), &error)) { - if (m_db->isModified()) { + if (m_db->isModified(true)) { // Ask if we want to merge changes into new database auto result = MessageBox::question( this, @@ -1513,6 +1667,11 @@ int DatabaseWidget::numberOfSelectedEntries() const return m_entryView->numberOfSelectedEntries(); } +int DatabaseWidget::currentEntryIndex() const +{ + return m_entryView->currentEntryIndex(); +} + QStringList DatabaseWidget::customEntryAttributes() const { Entry* entry = m_entryView->currentEntry(); @@ -1543,11 +1702,6 @@ bool DatabaseWidget::isGroupSelected() const return m_groupView->currentGroup(); } -bool DatabaseWidget::currentEntryHasFocus() -{ - return m_entryView->numberOfSelectedEntries() > 0 && m_entryView->hasFocus(); -} - bool DatabaseWidget::currentEntryHasTitle() { auto currentEntry = currentSelectedEntry(); @@ -1598,6 +1752,19 @@ bool DatabaseWidget::currentEntryHasTotp() return currentEntry->hasTotp(); } +#ifdef WITH_XC_SSHAGENT +bool DatabaseWidget::currentEntryHasSshKey() +{ + Entry* currentEntry = m_entryView->currentEntry(); + Q_ASSERT(currentEntry); + if (!currentEntry) { + return false; + } + + return KeeAgentSettings::inEntryAttachments(currentEntry->attachments()); +} +#endif + bool DatabaseWidget::currentEntryHasNotes() { auto currentEntry = currentSelectedEntry(); @@ -1654,9 +1821,9 @@ bool DatabaseWidget::save() m_groupView->setDisabled(true); QApplication::processEvents(); - bool useAtomicSaves = config()->get("UseAtomicSaves", true).toBool(); + bool useAtomicSaves = config()->get(Config::UseAtomicSaves).toBool(); QString errorMessage; - bool ok = m_db->save(&errorMessage, useAtomicSaves, config()->get("BackupBeforeSave").toBool()); + bool ok = m_db->save(&errorMessage, useAtomicSaves, config()->get(Config::BackupBeforeSave).toBool()); // Return control m_entryView->setDisabled(false); @@ -1682,7 +1849,7 @@ bool DatabaseWidget::save() MessageBox::Disable | MessageBox::Cancel, MessageBox::Disable); if (result == MessageBox::Disable) { - config()->set("UseAtomicSaves", false); + config()->set(Config::UseAtomicSaves, false); return save(); } } @@ -1702,14 +1869,75 @@ bool DatabaseWidget::save() */ bool DatabaseWidget::saveAs() { + // Never allow saving a locked database; it causes corruption + Q_ASSERT(!isLocked()); + // Release build interlock + if (isLocked()) { + // We return true since a save is not required + return true; + } + + QString oldFilePath = m_db->filePath(); + if (!QFileInfo::exists(oldFilePath)) { + oldFilePath = + QDir::toNativeSeparators(config()->get(Config::LastDir).toString() + "/" + tr("Passwords").append(".kdbx")); + } + const QString newFilePath = fileDialog()->getSaveFileName( + this, tr("Save database as"), oldFilePath, tr("KeePass 2 Database").append(" (*.kdbx)"), nullptr, nullptr); + + bool ok = false; + if (!newFilePath.isEmpty()) { + auto focusWidget = qApp->focusWidget(); + + // Lock out interactions + m_entryView->setDisabled(true); + m_groupView->setDisabled(true); + QApplication::processEvents(); + + QString errorMessage; + ok = m_db->saveAs(newFilePath, + &errorMessage, + config()->get(Config::UseAtomicSaves).toBool(), + config()->get(Config::BackupBeforeSave).toBool()); + + // Return control + m_entryView->setDisabled(false); + m_groupView->setDisabled(false); + + if (focusWidget) { + focusWidget->setFocus(); + } + + if (!ok) { + showMessage(tr("Writing the database failed: %1").arg(errorMessage), + MessageWidget::Error, + true, + MessageWidget::LongAutoHideTimeout); + } + } + + return ok; +} + +/** + * Save copy of database under a new user-selected filename. + * + * @return true on success + */ +bool DatabaseWidget::saveBackup() +{ while (true) { QString oldFilePath = m_db->filePath(); if (!QFileInfo::exists(oldFilePath)) { - oldFilePath = QDir::toNativeSeparators(config()->get("LastDir", QDir::homePath()).toString() + "/" + oldFilePath = QDir::toNativeSeparators(config()->get(Config::LastDir).toString() + "/" + tr("Passwords").append(".kdbx")); } - const QString newFilePath = fileDialog()->getSaveFileName( - this, tr("Save database as"), oldFilePath, tr("KeePass 2 Database").append(" (*.kdbx)"), nullptr, nullptr); + const QString newFilePath = fileDialog()->getSaveFileName(this, + tr("Save database backup"), + oldFilePath, + tr("KeePass 2 Database").append(" (*.kdbx)"), + nullptr, + nullptr); if (!newFilePath.isEmpty()) { // Ensure we don't recurse back into this function @@ -1717,11 +1945,19 @@ bool DatabaseWidget::saveAs() m_db->setFilePath(newFilePath); m_saveAttempts = 0; + bool modified = m_db->isModified(); + if (!save()) { // Failed to save, try again + m_db->setFilePath(oldFilePath); continue; } + m_db->setFilePath(oldFilePath); + if (modified) { + // Source database is marked as clean when copy is saved, even if source has unsaved changes + m_db->markAsModified(); + } return true; } @@ -1788,38 +2024,73 @@ void DatabaseWidget::processAutoOpen() if (entry->url().isEmpty() || (entry->password().isEmpty() && entry->username().isEmpty())) { continue; } - QFileInfo filepath; - QFileInfo keyfile; - if (entry->url().startsWith("file://")) { - QUrl url(entry->url()); - filepath.setFile(url.toLocalFile()); - } else { - filepath.setFile(entry->url()); - if (filepath.isRelative()) { - QFileInfo currentpath(m_db->filePath()); - filepath.setFile(currentpath.absoluteDir(), entry->url()); + // Support ifDevice advanced entry, a comma separated list of computer names + // that control whether to perform AutoOpen on this entry or not. Can be + // negated using '!' + auto ifDevice = entry->attribute("ifDevice"); + if (!ifDevice.isEmpty()) { + bool loadDb = false; + auto hostName = QHostInfo::localHostName(); + for (auto& dev : ifDevice.split(",")) { + dev = dev.trimmed(); + if (dev.startsWith("!") && dev.mid(1).compare(hostName, Qt::CaseInsensitive) == 0) { + // Machine name matched an exclusion, don't load this database + loadDb = false; + break; + } else if (dev.compare(hostName, Qt::CaseInsensitive) == 0) { + loadDb = true; + } + } + if (!loadDb) { + continue; } } - if (!filepath.isFile()) { - continue; + openDatabaseFromEntry(entry); + } +} + +void DatabaseWidget::openDatabaseFromEntry(const Entry* entry, bool inBackground) +{ + auto keyFile = entry->resolveMultiplePlaceholders(entry->username()); + auto password = entry->resolveMultiplePlaceholders(entry->password()); + auto databaseUrl = entry->resolveMultiplePlaceholders(entry->url()); + if (databaseUrl.startsWith("kdbx://")) { + databaseUrl = databaseUrl.mid(7); + } + + QFileInfo dbFileInfo; + if (databaseUrl.startsWith("file://")) { + QUrl url(databaseUrl); + dbFileInfo.setFile(url.toLocalFile()); + } else { + dbFileInfo.setFile(databaseUrl); + if (dbFileInfo.isRelative()) { + QFileInfo currentpath(m_db->filePath()); + dbFileInfo.setFile(currentpath.absoluteDir(), databaseUrl); } + } - if (!entry->username().isEmpty()) { - if (entry->username().startsWith("file://")) { - QUrl keyfileUrl(entry->username()); - keyfile.setFile(keyfileUrl.toLocalFile()); - } else { - keyfile.setFile(entry->username()); - if (keyfile.isRelative()) { - QFileInfo currentpath(m_db->filePath()); - keyfile.setFile(currentpath.absoluteDir(), entry->username()); - } + if (!dbFileInfo.isFile()) { + showErrorMessage(tr("Could not find database file: %1").arg(databaseUrl)); + return; + } + + QFileInfo keyFileInfo; + if (!keyFile.isEmpty()) { + if (keyFile.startsWith("file://")) { + QUrl keyfileUrl(keyFile); + keyFileInfo.setFile(keyfileUrl.toLocalFile()); + } else { + keyFileInfo.setFile(keyFile); + if (keyFileInfo.isRelative()) { + QFileInfo currentpath(m_db->filePath()); + keyFileInfo.setFile(currentpath.absoluteDir(), keyFile); } } - - // Request to open the database file in the background with a password and keyfile - emit requestOpenDatabase(filepath.canonicalFilePath(), true, entry->password(), keyfile.canonicalFilePath()); } + + // Request to open the database file in the background with a password and keyfile + emit requestOpenDatabase(dbFileInfo.canonicalFilePath(), inBackground, password, keyFileInfo.canonicalFilePath()); } |