Add 'get-database-entries' Proxy Request (#7292)

This commit is contained in:
Marcel Lauhoff 2023-02-25 20:09:36 +01:00 committed by GitHub
parent 56178f976a
commit 8a554b37c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 110 additions and 1 deletions

View File

@ -1122,6 +1122,14 @@ Do you want to delete the entry?
<source>Select native messaging host folder location</source> <source>Select native messaging host folder location</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Allow limited access to all entries in connected databases (ignores site access restrictions)</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CloneDialog</name> <name>CloneDialog</name>
@ -7925,6 +7933,10 @@ Kernel: %3 %4</source>
<source>Invalid KDF</source> <source>Invalid KDF</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Access to all entries is denied</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>QtIOCompressor</name> <name>QtIOCompressor</name>

View File

@ -17,6 +17,7 @@
#include "BrowserAction.h" #include "BrowserAction.h"
#include "BrowserService.h" #include "BrowserService.h"
#include "BrowserSettings.h"
#include "core/Global.h" #include "core/Global.h"
#include "core/Tools.h" #include "core/Tools.h"
@ -101,6 +102,8 @@ QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject&
return handleDeleteEntry(json, action); return handleDeleteEntry(json, action);
} else if (action.compare(BROWSER_REQUEST_REQUEST_AUTOTYPE) == 0) { } else if (action.compare(BROWSER_REQUEST_REQUEST_AUTOTYPE) == 0) {
return handleGlobalAutoType(json, action); return handleGlobalAutoType(json, action);
} else if (action.compare("get-database-entries", Qt::CaseSensitive) == 0) {
return handleGetDatabaseEntries(json, action);
} }
// Action was not recognized // Action was not recognized
@ -376,6 +379,40 @@ QJsonObject BrowserAction::handleGetDatabaseGroups(const QJsonObject& json, cons
return buildResponse(action, browserRequest.incrementedNonce, params); return buildResponse(action, browserRequest.incrementedNonce, params);
} }
QJsonObject BrowserAction::handleGetDatabaseEntries(const QJsonObject& json, const QString& action)
{
const QString hash = browserService()->getDatabaseHash();
const QString nonce = json.value("nonce").toString();
const QString encrypted = json.value("message").toString();
if (!m_associated) {
return getErrorReply(action, ERROR_KEEPASS_ASSOCIATION_FAILED);
}
const auto browserRequest = decodeRequest(json);
if (browserRequest.isEmpty()) {
return getErrorReply(action, ERROR_KEEPASS_CANNOT_DECRYPT_MESSAGE);
}
const auto command = browserRequest.getString("action");
if (command.isEmpty() || command.compare("get-database-entries") != 0) {
return getErrorReply(action, ERROR_KEEPASS_INCORRECT_ACTION);
}
if (!browserSettings()->allowGetDatabaseEntriesRequest()) {
return getErrorReply(action, ERROR_KEEPASS_ACCESS_TO_ALL_ENTRIES_DENIED);
}
const QJsonArray entries = browserService()->getDatabaseEntries();
if (entries.isEmpty()) {
return getErrorReply(action, ERROR_KEEPASS_NO_GROUPS_FOUND);
}
const Parameters params{{"entries", entries}};
return buildResponse(action, browserRequest.incrementedNonce, params);
}
QJsonObject BrowserAction::handleCreateNewGroup(const QJsonObject& json, const QString& action) QJsonObject BrowserAction::handleCreateNewGroup(const QJsonObject& json, const QString& action)
{ {
if (!m_associated) { if (!m_associated) {

View File

@ -68,6 +68,7 @@ private:
QJsonObject handleSetLogin(const QJsonObject& json, const QString& action); QJsonObject handleSetLogin(const QJsonObject& json, const QString& action);
QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action); QJsonObject handleLockDatabase(const QJsonObject& json, const QString& action);
QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action); QJsonObject handleGetDatabaseGroups(const QJsonObject& json, const QString& action);
QJsonObject handleGetDatabaseEntries(const QJsonObject& json, const QString& action);
QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action); QJsonObject handleCreateNewGroup(const QJsonObject& json, const QString& action);
QJsonObject handleGetTotp(const QJsonObject& json, const QString& action); QJsonObject handleGetTotp(const QJsonObject& json, const QString& action);
QJsonObject handleDeleteEntry(const QJsonObject& json, const QString& action); QJsonObject handleDeleteEntry(const QJsonObject& json, const QString& action);

View File

@ -123,6 +123,8 @@ QString BrowserMessageBuilder::getErrorMessage(const int errorCode) const
return QObject::tr("Cannot create new group"); return QObject::tr("Cannot create new group");
case ERROR_KEEPASS_NO_VALID_UUID_PROVIDED: case ERROR_KEEPASS_NO_VALID_UUID_PROVIDED:
return QObject::tr("No valid UUID provided"); return QObject::tr("No valid UUID provided");
case ERROR_KEEPASS_ACCESS_TO_ALL_ENTRIES_DENIED:
return QObject::tr("Access to all entries is denied");
default: default:
return QObject::tr("Unknown error"); return QObject::tr("Unknown error");
} }

View File

@ -47,7 +47,8 @@ namespace
ERROR_KEEPASS_NO_LOGINS_FOUND = 15, ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
ERROR_KEEPASS_NO_GROUPS_FOUND = 16, ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17, ERROR_KEEPASS_CANNOT_CREATE_NEW_GROUP = 17,
ERROR_KEEPASS_NO_VALID_UUID_PROVIDED = 18 ERROR_KEEPASS_NO_VALID_UUID_PROVIDED = 18,
ERROR_KEEPASS_ACCESS_TO_ALL_ENTRIES_DENIED = 19
}; };
} }

View File

@ -219,6 +219,35 @@ QJsonObject BrowserService::getDatabaseGroups()
return result; return result;
} }
QJsonArray BrowserService::getDatabaseEntries()
{
auto db = getDatabase();
if (!db) {
return {};
}
Group* rootGroup = db->rootGroup();
if (!rootGroup) {
return {};
}
QJsonArray entries;
for (const auto& group : rootGroup->groupsRecursive(true)) {
if (group == db->metadata()->recycleBin()) {
continue;
}
for (const auto& entry : group->entries()) {
QJsonObject jentry;
jentry["title"] = entry->resolveMultiplePlaceholders(entry->title());
jentry["uuid"] = entry->resolveMultiplePlaceholders(entry->uuidToHex());
jentry["url"] = entry->resolveMultiplePlaceholders(entry->url());
entries.push_back(jentry);
}
}
return entries;
}
QJsonObject BrowserService::createNewGroup(const QString& groupName) QJsonObject BrowserService::createNewGroup(const QString& groupName)
{ {
auto db = getDatabase(); auto db = getDatabase();

View File

@ -76,6 +76,7 @@ public:
void lockDatabase(); void lockDatabase();
QJsonObject getDatabaseGroups(); QJsonObject getDatabaseGroups();
QJsonArray getDatabaseEntries();
QJsonObject createNewGroup(const QString& groupName); QJsonObject createNewGroup(const QString& groupName);
QString getCurrentTotp(const QString& uuid); QString getCurrentTotp(const QString& uuid);
void showPasswordGenerator(const KeyPairMessage& keyPairMessage); void showPasswordGenerator(const KeyPairMessage& keyPairMessage);

View File

@ -222,6 +222,16 @@ void BrowserSettings::setUpdateBinaryPath(bool enabled)
config()->set(Config::Browser_UpdateBinaryPath, enabled); config()->set(Config::Browser_UpdateBinaryPath, enabled);
} }
bool BrowserSettings::allowGetDatabaseEntriesRequest()
{
return config()->get(Config::Browser_AllowGetDatabaseEntriesRequest).toBool();
}
void BrowserSettings::setAllowGetDatabaseEntriesRequest(bool enabled)
{
config()->set(Config::Browser_AllowGetDatabaseEntriesRequest, enabled);
}
bool BrowserSettings::allowExpiredCredentials() bool BrowserSettings::allowExpiredCredentials()
{ {
return config()->get(Config::Browser_AllowExpiredCredentials).toBool(); return config()->get(Config::Browser_AllowExpiredCredentials).toBool();

View File

@ -63,6 +63,8 @@ public:
#endif #endif
bool updateBinaryPath(); bool updateBinaryPath();
void setUpdateBinaryPath(bool enabled); void setUpdateBinaryPath(bool enabled);
bool allowGetDatabaseEntriesRequest();
void setAllowGetDatabaseEntriesRequest(bool enabled);
bool allowExpiredCredentials(); bool allowExpiredCredentials();
void setAllowExpiredCredentials(bool enabled); void setAllowExpiredCredentials(bool enabled);

View File

@ -125,6 +125,7 @@ void BrowserSettingsWidget::loadSettings()
m_ui->useCustomProxy->setChecked(settings->useCustomProxy()); m_ui->useCustomProxy->setChecked(settings->useCustomProxy());
m_ui->customProxyLocation->setText(settings->replaceHomePath(settings->customProxyLocation())); m_ui->customProxyLocation->setText(settings->replaceHomePath(settings->customProxyLocation()));
m_ui->updateBinaryPath->setChecked(settings->updateBinaryPath()); m_ui->updateBinaryPath->setChecked(settings->updateBinaryPath());
m_ui->allowGetDatabaseEntriesRequest->setChecked(settings->allowGetDatabaseEntriesRequest());
m_ui->allowExpiredCredentials->setChecked(settings->allowExpiredCredentials()); m_ui->allowExpiredCredentials->setChecked(settings->allowExpiredCredentials());
m_ui->chromeSupport->setChecked(settings->browserSupport(BrowserShared::CHROME)); m_ui->chromeSupport->setChecked(settings->browserSupport(BrowserShared::CHROME));
m_ui->chromiumSupport->setChecked(settings->browserSupport(BrowserShared::CHROMIUM)); m_ui->chromiumSupport->setChecked(settings->browserSupport(BrowserShared::CHROMIUM));
@ -217,6 +218,7 @@ void BrowserSettingsWidget::saveSettings()
settings->setCustomProxyLocation(browserSettings()->replaceTildeHomePath(m_ui->customProxyLocation->text())); settings->setCustomProxyLocation(browserSettings()->replaceTildeHomePath(m_ui->customProxyLocation->text()));
settings->setUpdateBinaryPath(m_ui->updateBinaryPath->isChecked()); settings->setUpdateBinaryPath(m_ui->updateBinaryPath->isChecked());
settings->setAllowGetDatabaseEntriesRequest(m_ui->allowGetDatabaseEntriesRequest->isChecked());
settings->setAllowExpiredCredentials(m_ui->allowExpiredCredentials->isChecked()); settings->setAllowExpiredCredentials(m_ui->allowExpiredCredentials->isChecked());
settings->setAlwaysAllowAccess(m_ui->alwaysAllowAccess->isChecked()); settings->setAlwaysAllowAccess(m_ui->alwaysAllowAccess->isChecked());
settings->setAlwaysAllowUpdate(m_ui->alwaysAllowUpdate->isChecked()); settings->setAlwaysAllowUpdate(m_ui->alwaysAllowUpdate->isChecked());

View File

@ -327,6 +327,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="allowGetDatabaseEntriesRequest">
<property name="toolTip">
<string>Allow keepassxc-proxy to list all entries with their title, URL and UUID in connected databases.</string>
</property>
<property name="text">
<string>Allow limited access to all entries in connected databases (ignores site access restrictions)</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="useCustomProxy"> <widget class="QCheckBox" name="useCustomProxy">
<property name="toolTip"> <property name="toolTip">

View File

@ -155,6 +155,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::Browser_UseCustomProxy, {QS("Browser/UseCustomProxy"), Roaming, false}}, {Config::Browser_UseCustomProxy, {QS("Browser/UseCustomProxy"), Roaming, false}},
{Config::Browser_CustomProxyLocation, {QS("Browser/CustomProxyLocation"), Roaming, {}}}, {Config::Browser_CustomProxyLocation, {QS("Browser/CustomProxyLocation"), Roaming, {}}},
{Config::Browser_UpdateBinaryPath, {QS("Browser/UpdateBinaryPath"), Roaming, true}}, {Config::Browser_UpdateBinaryPath, {QS("Browser/UpdateBinaryPath"), Roaming, true}},
{Config::Browser_AllowGetDatabaseEntriesRequest, {QS("Browser/AllowGetDatabaseEntriesRequest"), Roaming, false}},
{Config::Browser_AllowExpiredCredentials, {QS("Browser/AllowExpiredCredentials"), Roaming, false}}, {Config::Browser_AllowExpiredCredentials, {QS("Browser/AllowExpiredCredentials"), Roaming, false}},
{Config::Browser_AlwaysAllowAccess, {QS("Browser/AlwaysAllowAccess"), Roaming, false}}, {Config::Browser_AlwaysAllowAccess, {QS("Browser/AlwaysAllowAccess"), Roaming, false}},
{Config::Browser_AlwaysAllowUpdate, {QS("Browser/AlwaysAllowUpdate"), Roaming, false}}, {Config::Browser_AlwaysAllowUpdate, {QS("Browser/AlwaysAllowUpdate"), Roaming, false}},

View File

@ -134,6 +134,7 @@ public:
Browser_UseCustomProxy, Browser_UseCustomProxy,
Browser_CustomProxyLocation, Browser_CustomProxyLocation,
Browser_UpdateBinaryPath, Browser_UpdateBinaryPath,
Browser_AllowGetDatabaseEntriesRequest,
Browser_AllowExpiredCredentials, Browser_AllowExpiredCredentials,
Browser_AlwaysAllowAccess, Browser_AlwaysAllowAccess,
Browser_AlwaysAllowUpdate, Browser_AlwaysAllowUpdate,