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>
<translation type="unfinished"></translation>
</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>
<name>CloneDialog</name>
@ -7925,6 +7933,10 @@ Kernel: %3 %4</source>
<source>Invalid KDF</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Access to all entries is denied</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtIOCompressor</name>

View File

@ -17,6 +17,7 @@
#include "BrowserAction.h"
#include "BrowserService.h"
#include "BrowserSettings.h"
#include "core/Global.h"
#include "core/Tools.h"
@ -101,6 +102,8 @@ QJsonObject BrowserAction::handleAction(QLocalSocket* socket, const QJsonObject&
return handleDeleteEntry(json, action);
} else if (action.compare(BROWSER_REQUEST_REQUEST_AUTOTYPE) == 0) {
return handleGlobalAutoType(json, action);
} else if (action.compare("get-database-entries", Qt::CaseSensitive) == 0) {
return handleGetDatabaseEntries(json, action);
}
// Action was not recognized
@ -376,6 +379,40 @@ QJsonObject BrowserAction::handleGetDatabaseGroups(const QJsonObject& json, cons
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)
{
if (!m_associated) {

View File

@ -68,6 +68,7 @@ private:
QJsonObject handleSetLogin(const QJsonObject& json, const QString& action);
QJsonObject handleLockDatabase(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 handleGetTotp(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");
case ERROR_KEEPASS_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:
return QObject::tr("Unknown error");
}

View File

@ -47,7 +47,8 @@ namespace
ERROR_KEEPASS_NO_LOGINS_FOUND = 15,
ERROR_KEEPASS_NO_GROUPS_FOUND = 16,
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;
}
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)
{
auto db = getDatabase();

View File

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

View File

@ -222,6 +222,16 @@ void BrowserSettings::setUpdateBinaryPath(bool 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()
{
return config()->get(Config::Browser_AllowExpiredCredentials).toBool();

View File

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

View File

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

View File

@ -327,6 +327,16 @@
</property>
</widget>
</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>
<widget class="QCheckBox" name="useCustomProxy">
<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_CustomProxyLocation, {QS("Browser/CustomProxyLocation"), Roaming, {}}},
{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_AlwaysAllowAccess, {QS("Browser/AlwaysAllowAccess"), Roaming, false}},
{Config::Browser_AlwaysAllowUpdate, {QS("Browser/AlwaysAllowUpdate"), Roaming, false}},

View File

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