[Servatrice] Match trusted_sources by address, not substring (#7582)

trusted_sources was checked with QString::contains. A dual-stack listener
reports a local proxy as ::ffff:127.0.0.1, which never matches the default
"127.0.0.1,::1". Behind nginx the forwarded client IP header was then
ignored, every websocket user shared the proxy's address, and logins
failed with "too many concurrent connections" once max_users_per_address
was reached.

Add isTrustedSource(), which parses each entry as a QHostAddress and
compares exact addresses with IPv4-mapped addresses normalized, and use it
at all four call sites. The ban command also read server/trusted_sources
instead of the documented security/trusted_sources; it now uses the same
getter. Entries that are not IP addresses are logged at startup since they
no longer match anything.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Zach H 2026-10-18 16:50:04 -04:00 • committed by GitHub
parent 4343544588
commit 46cdbac830
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 136 additions and 9 deletions

View file

@ -0,0 +1,23 @@
#include "trusted_sources.h"
#include <QStringList>
bool isTrustedSource(const QString &trustedSources, const QHostAddress &address)
{
if (address.isNull()) {
return false;
}
const QStringList entries = trustedSources.split(',', Qt::SkipEmptyParts);
for (const QString &entry : entries) {
const QHostAddress trusted(entry.trimmed());
if (!trusted.isNull() && trusted.isEqual(address, QHostAddress::ConvertV4MappedToIPv4)) {
return true;
}
}
return false;
}
bool isTrustedSource(const QString &trustedSources, const QString &address)
{
return isTrustedSource(trustedSources, QHostAddress(address.trimmed()));
}