diff options
Diffstat (limited to 'src/browser/BrowserService.cpp')
-rw-r--r-- | src/browser/BrowserService.cpp | 437 |
1 files changed, 217 insertions, 220 deletions
diff --git a/src/browser/BrowserService.cpp b/src/browser/BrowserService.cpp index 42def203a..1f54e33ca 100644 --- a/src/browser/BrowserService.cpp +++ b/src/browser/BrowserService.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2013 Francois Ferrand * Copyright (C) 2017 Sami Vänttinen <sami.vanttinen@protonmail.com> - * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org> + * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org> * * 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 @@ -26,8 +26,10 @@ #include <QUuid> #include "BrowserAccessControlDialog.h" +#include "BrowserAction.h" #include "BrowserEntryConfig.h" #include "BrowserEntrySaveDialog.h" +#include "BrowserHost.h" #include "BrowserService.h" #include "BrowserSettings.h" #include "core/Database.h" @@ -39,16 +41,14 @@ #include "gui/MainWindow.h" #include "gui/MessageBox.h" #ifdef Q_OS_MACOS -#include "gui/macutils/MacUtils.h" +#include "gui/osutils/macutils/MacUtils.h" #endif const QString BrowserService::KEEPASSXCBROWSER_NAME = QStringLiteral("KeePassXC-Browser Settings"); const QString BrowserService::KEEPASSXCBROWSER_OLD_NAME = QStringLiteral("keepassxc-browser Settings"); -const QString BrowserService::ASSOCIATE_KEY_PREFIX = QStringLiteral("KPXC_BROWSER_"); static const QString KEEPASSXCBROWSER_GROUP_NAME = QStringLiteral("KeePassXC-Browser Passwords"); static int KEEPASSXCBROWSER_DEFAULT_ICON = 1; // These are for the settings and password conversion -const QString BrowserService::LEGACY_ASSOCIATE_KEY_PREFIX = QStringLiteral("Public Key: "); static const QString KEEPASSHTTP_NAME = QStringLiteral("KeePassHttp Settings"); static const QString KEEPASSHTTP_GROUP_NAME = QStringLiteral("KeePassHttp Passwords"); // Extra entry related options saved in custom data @@ -58,34 +58,45 @@ const QString BrowserService::OPTION_ONLY_HTTP_AUTH = QStringLiteral("BrowserOnl // Multiple URL's const QString BrowserService::ADDITIONAL_URL = QStringLiteral("KP2A_URL"); -BrowserService::BrowserService(DatabaseTabWidget* parent) - : m_dbTabWidget(parent) +Q_GLOBAL_STATIC(BrowserService, s_browserService); + +BrowserService::BrowserService() + : QObject() + , m_browserHost(new BrowserHost) , m_dialogActive(false) , m_bringToFrontRequested(false) , m_prevWindowState(WindowState::Normal) , m_keepassBrowserUUID(Tools::hexToUuid("de887cc3036343b8974b5911b8816224")) { - // Don't connect the signals when used from DatabaseSettingsWidgetBrowser (parent is nullptr) - if (m_dbTabWidget) { - connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), this, SLOT(databaseLocked(DatabaseWidget*))); - connect( - m_dbTabWidget, SIGNAL(databaseUnlocked(DatabaseWidget*)), this, SLOT(databaseUnlocked(DatabaseWidget*))); - connect(m_dbTabWidget, - SIGNAL(activateDatabaseChanged(DatabaseWidget*)), - this, - SLOT(activateDatabaseChanged(DatabaseWidget*))); + connect(m_browserHost, &BrowserHost::clientMessageReceived, this, &BrowserService::processClientMessage); + setEnabled(browserSettings()->isEnabled()); +} + +BrowserService* BrowserService::instance() +{ + return s_browserService; +} + +void BrowserService::setEnabled(bool enabled) +{ + if (enabled) { + // Update KeePassXC/keepassxc-proxy binary paths to Native Messaging scripts + if (browserSettings()->updateBinaryPath()) { + browserSettings()->updateBinaryPaths(); + } + + m_browserHost->start(); + } else { + m_browserHost->stop(); } } bool BrowserService::isDatabaseOpened() const { - DatabaseWidget* dbWidget = m_dbTabWidget->currentDatabaseWidget(); - if (!dbWidget) { - return false; + if (m_currentDatabaseWidget) { + return !m_currentDatabaseWidget->isLocked(); } - - return dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode - || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode; + return false; } bool BrowserService::openDatabase(bool triggerUnlock) @@ -94,19 +105,14 @@ bool BrowserService::openDatabase(bool triggerUnlock) return false; } - DatabaseWidget* dbWidget = m_dbTabWidget->currentDatabaseWidget(); - if (!dbWidget) { - return false; - } - - if (dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode - || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode) { + if (m_currentDatabaseWidget && !m_currentDatabaseWidget->isLocked()) { return true; } if (triggerUnlock) { m_bringToFrontRequested = true; - raiseWindow(true); + updateWindowState(); + emit requestUnlock(); } return false; @@ -114,19 +120,20 @@ bool BrowserService::openDatabase(bool triggerUnlock) void BrowserService::lockDatabase() { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "lockDatabase", Qt::BlockingQueuedConnection); - } - - DatabaseWidget* dbWidget = m_dbTabWidget->currentDatabaseWidget(); - if (!dbWidget) { - return; + if (m_currentDatabaseWidget) { + m_currentDatabaseWidget->lock(); } +} - if (dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode - || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode) { - dbWidget->lock(); +QString BrowserService::getDatabaseHash(bool legacy) +{ + if (legacy) { + return QCryptographicHash::hash( + (browserService()->getDatabaseRootUuid() + browserService()->getDatabaseRecycleBinUuid()).toUtf8(), + QCryptographicHash::Sha256) + .toHex(); } + return QCryptographicHash::hash(getDatabaseRootUuid().toUtf8(), QCryptographicHash::Sha256).toHex(); } QString BrowserService::getDatabaseRootUuid() @@ -180,9 +187,9 @@ QJsonArray BrowserService::getChildrenFromGroup(Group* group) return groupList; } -QJsonObject BrowserService::getDatabaseGroups(const QSharedPointer<Database>& selectedDb) +QJsonObject BrowserService::getDatabaseGroups() { - auto db = selectedDb ? selectedDb : getDatabase(); + auto db = getDatabase(); if (!db) { return {}; } @@ -208,15 +215,6 @@ QJsonObject BrowserService::getDatabaseGroups(const QSharedPointer<Database>& se QJsonObject BrowserService::createNewGroup(const QString& groupName) { - QJsonObject result; - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, - "createNewGroup", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QJsonObject, result), - Q_ARG(QString, groupName)); - return result; - } auto db = getDatabase(); if (!db) { @@ -232,6 +230,7 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) // Group already exists if (group) { + QJsonObject result; result["name"] = group->name(); result["uuid"] = Tools::uuidToHex(group->uuid()); return result; @@ -245,7 +244,7 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) MessageBox::Yes | MessageBox::No); if (dialogResult != MessageBox::Yes) { - return result; + return {}; } QString name, uuid; @@ -279,6 +278,7 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) previousGroup = tempGroup; } + QJsonObject result; result["name"] = name; result["uuid"] = uuid; return result; @@ -286,25 +286,18 @@ QJsonObject BrowserService::createNewGroup(const QString& groupName) QString BrowserService::storeKey(const QString& key) { - QString id; - - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod( - this, "storeKey", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, id), Q_ARG(QString, key)); - return id; - } - auto db = getDatabase(); if (!db) { return {}; } bool contains; - MessageBox::Button dialogResult = MessageBox::Cancel; + auto dialogResult = MessageBox::Cancel; + QString id; do { QInputDialog keyDialog; - connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), &keyDialog, SLOT(reject())); + connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &keyDialog, SLOT(reject())); keyDialog.setWindowTitle(tr("KeePassXC: New key association request")); keyDialog.setLabelText(tr("You have received an association request for the following database:\n%1\n\n" "Give the connection a unique name or ID, for example:\nchrome-laptop.") @@ -324,7 +317,7 @@ QString BrowserService::storeKey(const QString& key) return {}; } - contains = db->metadata()->customData()->contains(ASSOCIATE_KEY_PREFIX + id); + contains = db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + id); if (contains) { dialogResult = MessageBox::warning(nullptr, tr("KeePassXC: Overwrite existing key?"), @@ -337,7 +330,9 @@ QString BrowserService::storeKey(const QString& key) } while (contains && dialogResult == MessageBox::Cancel); hideWindow(); - db->metadata()->customData()->set(ASSOCIATE_KEY_PREFIX + id, key); + db->metadata()->customData()->set(CustomData::BrowserKeyPrefix + id, key); + db->metadata()->customData()->set(QString("%1_%2").arg(CustomData::Created, id), + Clock::currentDateTime().toString(Qt::SystemLocaleShortDate)); return id; } @@ -348,31 +343,17 @@ QString BrowserService::getKey(const QString& id) return {}; } - return db->metadata()->customData()->value(ASSOCIATE_KEY_PREFIX + id); + return db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + id); } -QJsonArray BrowserService::findMatchingEntries(const QString& id, +QJsonArray BrowserService::findMatchingEntries(const QString& dbid, const QString& url, const QString& submitUrl, const QString& realm, const StringPairList& keyList, const bool httpAuth) { - QJsonArray result; - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, - "findMatchingEntries", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QJsonArray, result), - Q_ARG(QString, id), - Q_ARG(QString, url), - Q_ARG(QString, submitUrl), - Q_ARG(QString, realm), - Q_ARG(StringPairList, keyList), - Q_ARG(bool, httpAuth)); - return result; - } - + Q_UNUSED(dbid); const bool alwaysAllowAccess = browserSettings()->alwaysAllowAccess(); const bool ignoreHttpAuth = browserSettings()->httpAuthPermission(); const QString host = QUrl(url).host(); @@ -417,23 +398,25 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id, } // Confirm entries - if (confirmEntries(pwEntriesToConfirm, url, host, submitUrl, realm, httpAuth)) { - pwEntries.append(pwEntriesToConfirm); + QList<Entry*> selectedEntriesToConfirm = confirmEntries(pwEntriesToConfirm, url, host, submitHost, realm, httpAuth); + if (!selectedEntriesToConfirm.isEmpty()) { + pwEntries.append(selectedEntriesToConfirm); } if (pwEntries.isEmpty()) { - return QJsonArray(); + return {}; } // Ensure that database is not locked when the popup was visible if (!isDatabaseOpened()) { - return QJsonArray(); + return {}; } // Sort results pwEntries = sortEntries(pwEntries, host, submitUrl); // Fill the list + QJsonArray result; for (auto* entry : pwEntries) { result.append(prepareEntry(entry)); } @@ -441,7 +424,7 @@ QJsonArray BrowserService::findMatchingEntries(const QString& id, return result; } -void BrowserService::addEntry(const QString& id, +void BrowserService::addEntry(const QString& dbid, const QString& login, const QString& password, const QString& url, @@ -451,21 +434,8 @@ void BrowserService::addEntry(const QString& id, const QString& groupUuid, const QSharedPointer<Database>& selectedDb) { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, - "addEntry", - Qt::BlockingQueuedConnection, - Q_ARG(QString, id), - Q_ARG(QString, login), - Q_ARG(QString, password), - Q_ARG(QString, url), - Q_ARG(QString, submitUrl), - Q_ARG(QString, realm), - Q_ARG(QString, group), - Q_ARG(QString, groupUuid), - Q_ARG(QSharedPointer<Database>, selectedDb)); - } - + // TODO: select database based on this key id + Q_UNUSED(dbid); auto db = selectedDb ? selectedDb : selectedDatabase(); if (!db) { return; @@ -507,37 +477,25 @@ void BrowserService::addEntry(const QString& id, config.save(entry); } -BrowserService::ReturnValue BrowserService::updateEntry(const QString& id, - const QString& uuid, - const QString& login, - const QString& password, - const QString& url, - const QString& submitUrl) +bool BrowserService::updateEntry(const QString& dbid, + const QString& uuid, + const QString& login, + const QString& password, + const QString& url, + const QString& submitUrl) { - ReturnValue result = ReturnValue::Error; - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, - "updateEntry", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(ReturnValue, result), - Q_ARG(QString, id), - Q_ARG(QString, uuid), - Q_ARG(QString, login), - Q_ARG(QString, password), - Q_ARG(QString, url), - Q_ARG(QString, submitUrl)); - } - + // TODO: select database based on this key id + Q_UNUSED(dbid); auto db = selectedDatabase(); if (!db) { - return ReturnValue::Error; + return false; } Entry* entry = db->rootGroup()->findEntryByUuid(Tools::hexToUuid(uuid)); if (!entry) { // If entry is not found for update, add a new one to the selected database - addEntry(id, login, password, url, submitUrl, "", "", "", db); - return ReturnValue::Success; + addEntry(dbid, login, password, url, submitUrl, "", "", "", db); + return true; } // Check if the entry password is a reference. If so, update the original entry instead @@ -546,16 +504,17 @@ BrowserService::ReturnValue BrowserService::updateEntry(const QString& id, if (!referenceUuid.isNull()) { entry = db->rootGroup()->findEntryByUuid(referenceUuid); if (!entry) { - return ReturnValue::Error; + return false; } } } QString username = entry->username(); if (username.isEmpty()) { - return ReturnValue::Error; + return false; } + bool result = false; if (username.compare(login, Qt::CaseSensitive) != 0 || entry->password().compare(password, Qt::CaseSensitive) != 0) { MessageBox::Button dialogResult = MessageBox::No; @@ -577,9 +536,7 @@ BrowserService::ReturnValue BrowserService::updateEntry(const QString& id, } entry->setPassword(password); entry->endUpdate(); - result = ReturnValue::Success; - } else { - result = ReturnValue::Canceled; + result = true; } hideWindow(); @@ -609,7 +566,8 @@ BrowserService::searchEntries(const QSharedPointer<Database>& db, const QString& // Search for additional URL's starting with KP2A_URL for (const auto& key : entry->attributes()->keys()) { - if (key.startsWith(ADDITIONAL_URL) && handleURL(entry->attributes()->value(key), url, submitUrl)) { + if (key.startsWith(ADDITIONAL_URL) && handleURL(entry->attributes()->value(key), url, submitUrl) + && !entries.contains(entry)) { entries.append(entry); continue; } @@ -631,7 +589,7 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const QString& s // Check if database is connected with KeePassXC-Browser auto databaseConnected = [&](const QSharedPointer<Database>& db) { for (const StringPair& keyPair : keyList) { - QString key = db->metadata()->customData()->value(ASSOCIATE_KEY_PREFIX + keyPair.first); + QString key = db->metadata()->customData()->value(CustomData::BrowserKeyPrefix + keyPair.first); if (!key.isEmpty() && keyPair.second == key) { return true; } @@ -642,17 +600,14 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const QString& s // Get the list of databases to search QList<QSharedPointer<Database>> databases; if (browserSettings()->searchInAllDatabases()) { - const int count = m_dbTabWidget->count(); - for (int i = 0; i < count; ++i) { - if (auto* dbWidget = qobject_cast<DatabaseWidget*>(m_dbTabWidget->widget(i))) { - if (const auto& db = dbWidget->database()) { - if (databaseConnected(db)) { - databases << db; - } - } + for (auto dbWidget : getMainWindow()->getOpenDatabases()) { + auto db = dbWidget->database(); + if (db && databaseConnected(dbWidget->database())) { + databases << db; } } - } else if (const auto& db = getDatabase()) { + } else { + const auto& db = getDatabase(); if (databaseConnected(db)) { databases << db; } @@ -670,9 +625,8 @@ QList<Entry*> BrowserService::searchEntries(const QString& url, const QString& s return entries; } -void BrowserService::convertAttributesToCustomData(const QSharedPointer<Database>& currentDb) +void BrowserService::convertAttributesToCustomData(QSharedPointer<Database> db) { - auto db = currentDb ? currentDb : getDatabase(); if (!db) { return; } @@ -702,7 +656,7 @@ void BrowserService::convertAttributesToCustomData(const QSharedPointer<Database if (entry->title() == KEEPASSHTTP_NAME || entry->title().contains(KEEPASSXCBROWSER_NAME, Qt::CaseInsensitive)) { keyCounter += moveKeysToCustomData(entry, db); - delete entry; + db->recycleEntry(entry); } progress.setValue(progress.value() + 1); @@ -788,59 +742,69 @@ QList<Entry*> BrowserService::sortEntries(QList<Entry*>& pwEntries, const QStrin return results; } -bool BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm, - const QString& url, - const QString& host, - const QString& submitUrl, - const QString& realm, - const bool httpAuth) +QList<Entry*> BrowserService::confirmEntries(QList<Entry*>& pwEntriesToConfirm, + const QString& url, + const QString& host, + const QString& submitHost, + const QString& realm, + const bool httpAuth) { if (pwEntriesToConfirm.isEmpty() || m_dialogActive) { - return false; + return {}; } m_dialogActive = true; + updateWindowState(); BrowserAccessControlDialog accessControlDialog; - connect(m_dbTabWidget, SIGNAL(databaseLocked(DatabaseWidget*)), &accessControlDialog, SLOT(reject())); - accessControlDialog.setUrl(!submitUrl.isEmpty() ? submitUrl : url); - accessControlDialog.setItems(pwEntriesToConfirm); - accessControlDialog.setHTTPAuth(httpAuth); - raiseWindow(); - accessControlDialog.show(); - accessControlDialog.activateWindow(); - accessControlDialog.raise(); + connect(m_currentDatabaseWidget, SIGNAL(databaseLocked()), &accessControlDialog, SLOT(reject())); - const QString submitHost = QUrl(submitUrl).host(); - int res = accessControlDialog.exec(); - if (accessControlDialog.remember()) { - for (auto* entry : pwEntriesToConfirm) { - BrowserEntryConfig config; - config.load(entry); - if (res == QDialog::Accepted) { + connect(&accessControlDialog, &BrowserAccessControlDialog::disableAccess, [&](QTableWidgetItem* item) { + auto entry = pwEntriesToConfirm[item->row()]; + BrowserEntryConfig config; + config.load(entry); + config.deny(host); + if (!submitHost.isEmpty() && host != submitHost) { + config.deny(submitHost); + } + if (!realm.isEmpty()) { + config.setRealm(realm); + } + config.save(entry); + }); + + accessControlDialog.setItems(pwEntriesToConfirm, !submitHost.isEmpty() ? submitHost : url, httpAuth); + + QList<Entry*> allowedEntries; + if (accessControlDialog.exec() == QDialog::Accepted) { + const auto selectedEntries = accessControlDialog.getSelectedEntries(); + for (auto item : accessControlDialog.getSelectedEntries()) { + auto entry = pwEntriesToConfirm[item->row()]; + if (accessControlDialog.remember()) { + BrowserEntryConfig config; + config.load(entry); config.allow(host); - if (!submitHost.isEmpty() && host != submitHost) - config.allow(submitHost); - } else if (res == QDialog::Rejected) { - config.deny(host); if (!submitHost.isEmpty() && host != submitHost) { - config.deny(submitHost); + config.allow(submitHost); } + if (!realm.isEmpty()) { + config.setRealm(realm); + } + config.save(entry); } - if (!realm.isEmpty()) { - config.setRealm(realm); - } - config.save(entry); + allowedEntries.append(entry); } } - m_dialogActive = false; +#ifdef Q_OS_MAC + // Re-hide the application if it wasn't visible before + // only affects macOS because dialogs force the main window to show hideWindow(); - if (res == QDialog::Accepted) { - return true; - } +#endif - return false; + m_dialogActive = false; + + return allowedEntries; } QJsonObject BrowserService::prepareEntry(const Entry* entry) @@ -850,6 +814,7 @@ QJsonObject BrowserService::prepareEntry(const Entry* entry) res["password"] = entry->resolveMultiplePlaceholders(entry->password()); res["name"] = entry->resolveMultiplePlaceholders(entry->title()); res["uuid"] = entry->resolveMultiplePlaceholders(entry->uuidToHex()); + res["group"] = entry->resolveMultiplePlaceholders(entry->group()->name()); if (entry->hasTotp()) { res["totp"] = entry->totp(); @@ -881,13 +846,14 @@ QJsonObject BrowserService::prepareEntry(const Entry* entry) BrowserService::Access BrowserService::checkAccess(const Entry* entry, const QString& host, const QString& submitHost, const QString& realm) { + if (entry->isExpired()) { + return browserSettings()->allowExpiredCredentials() ? Allowed : Denied; + } + BrowserEntryConfig config; if (!config.load(entry)) { return Unknown; } - if (entry->isExpired()) { - return browserSettings()->allowExpiredCredentials() ? Allowed : Denied; - } if ((config.isAllowed(host)) && (submitHost.isEmpty() || config.isAllowed(submitHost))) { return Allowed; } @@ -1096,10 +1062,8 @@ QString BrowserService::baseDomain(const QString& hostname) const QSharedPointer<Database> BrowserService::getDatabase() { - if (DatabaseWidget* dbWidget = m_dbTabWidget->currentDatabaseWidget()) { - if (const auto& db = dbWidget->database()) { - return db; - } + if (m_currentDatabaseWidget) { + return m_currentDatabaseWidget->database(); } return {}; } @@ -1107,22 +1071,15 @@ QSharedPointer<Database> BrowserService::getDatabase() QSharedPointer<Database> BrowserService::selectedDatabase() { QList<DatabaseWidget*> databaseWidgets; - for (int i = 0;; ++i) { - auto* dbWidget = m_dbTabWidget->databaseWidgetFromIndex(i); + for (auto dbWidget : getMainWindow()->getOpenDatabases()) { // Add only open databases - if (dbWidget && dbWidget->database()->hasKey() - && (dbWidget->currentMode() == DatabaseWidget::Mode::ViewMode - || dbWidget->currentMode() == DatabaseWidget::Mode::EditMode)) { - databaseWidgets.push_back(dbWidget); - continue; + if (!dbWidget->isLocked()) { + databaseWidgets << dbWidget; } - - // Break out if dbStruct.dbWidget is nullptr - break; } BrowserEntrySaveDialog browserEntrySaveDialog; - int openDatabaseCount = browserEntrySaveDialog.setItems(databaseWidgets, m_dbTabWidget->currentDatabaseWidget()); + int openDatabaseCount = browserEntrySaveDialog.setItems(databaseWidgets, m_currentDatabaseWidget); if (openDatabaseCount > 1) { int res = browserEntrySaveDialog.exec(); if (res == QDialog::Accepted) { @@ -1140,7 +1097,7 @@ QSharedPointer<Database> BrowserService::selectedDatabase() return getDatabase(); } -bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name) const +bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name) { if (entry->attributes()->contains(name)) { QString attr = entry->attributes()->value(name); @@ -1155,17 +1112,18 @@ bool BrowserService::moveSettingsToCustomData(Entry* entry, const QString& name) return false; } -int BrowserService::moveKeysToCustomData(Entry* entry, const QSharedPointer<Database>& db) const +int BrowserService::moveKeysToCustomData(Entry* entry, QSharedPointer<Database> db) { int keyCounter = 0; for (const auto& key : entry->attributes()->keys()) { - if (key.contains(LEGACY_ASSOCIATE_KEY_PREFIX)) { + if (key.contains(CustomData::BrowserLegacyKeyPrefix)) { QString publicKey = key; - publicKey.remove(LEGACY_ASSOCIATE_KEY_PREFIX); + publicKey.remove(CustomData::BrowserLegacyKeyPrefix); // Add key to database custom data - if (db && !db->metadata()->customData()->contains(ASSOCIATE_KEY_PREFIX + publicKey)) { - db->metadata()->customData()->set(ASSOCIATE_KEY_PREFIX + publicKey, entry->attributes()->value(key)); + if (db && !db->metadata()->customData()->contains(CustomData::BrowserKeyPrefix + publicKey)) { + db->metadata()->customData()->set(CustomData::BrowserKeyPrefix + publicKey, + entry->attributes()->value(key)); ++keyCounter; } } @@ -1174,14 +1132,9 @@ int BrowserService::moveKeysToCustomData(Entry* entry, const QSharedPointer<Data return keyCounter; } -bool BrowserService::checkLegacySettings() +bool BrowserService::checkLegacySettings(QSharedPointer<Database> db) { - if (!browserSettings()->isEnabled() || browserSettings()->noMigrationPrompt()) { - return false; - } - - auto db = getDatabase(); - if (!db) { + if (!db || !browserSettings()->isEnabled() || browserSettings()->noMigrationPrompt()) { return false; } @@ -1264,36 +1217,80 @@ void BrowserService::raiseWindow(const bool force) #endif } +void BrowserService::updateWindowState() +{ + m_prevWindowState = WindowState::Normal; + if (getMainWindow()->isMinimized()) { + m_prevWindowState = WindowState::Minimized; + } +#ifdef Q_OS_MACOS + if (macUtils()->isHidden()) { + m_prevWindowState = WindowState::Hidden; + } +#else + if (getMainWindow()->isHidden()) { + m_prevWindowState = WindowState::Hidden; + } +#endif +} + void BrowserService::databaseLocked(DatabaseWidget* dbWidget) { if (dbWidget) { - emit databaseLocked(); + QJsonObject msg; + msg["action"] = QString("database-locked"); + m_browserHost->sendClientMessage(msg); } } void BrowserService::databaseUnlocked(DatabaseWidget* dbWidget) { if (dbWidget) { +#ifdef Q_OS_MAC if (m_bringToFrontRequested) { - hideWindow(); m_bringToFrontRequested = false; + hideWindow(); } - emit databaseUnlocked(); +#endif + + QJsonObject msg; + msg["action"] = QString("database-unlocked"); + m_browserHost->sendClientMessage(msg); - if (checkLegacySettings()) { - convertAttributesToCustomData(); + auto db = dbWidget->database(); + if (checkLegacySettings(db)) { + convertAttributesToCustomData(db); } } } -void BrowserService::activateDatabaseChanged(DatabaseWidget* dbWidget) +void BrowserService::activeDatabaseChanged(DatabaseWidget* dbWidget) { - if (dbWidget) { - auto currentMode = dbWidget->currentMode(); - if (currentMode == DatabaseWidget::Mode::ViewMode || currentMode == DatabaseWidget::Mode::EditMode) { - emit databaseUnlocked(); + // Only emit these signals when we are not searching in all databases + if (dbWidget && !browserSettings()->searchInAllDatabases()) { + if (dbWidget->isLocked()) { + databaseLocked(dbWidget); } else { - emit databaseLocked(); + databaseUnlocked(dbWidget); } } + + m_currentDatabaseWidget = dbWidget; +} + +void BrowserService::processClientMessage(const QJsonObject& message) +{ + auto clientID = message["clientID"].toString(); + if (clientID.isEmpty()) { + return; + } + + // Create a new client action if we haven't seen this id yet + if (!m_browserClients.contains(clientID)) { + m_browserClients.insert(clientID, QSharedPointer<BrowserAction>::create()); + } + + auto& action = m_browserClients.value(clientID); + auto response = action->processClientMessage(message); + m_browserHost->sendClientMessage(response); } |