TASK-030: Secure IP geolocation with MMDB-primary resolver

Make MaxMind GeoLite2-Country MMDB the primary IP resolver (local, encrypted)
and demote ip-api.com to optional fallback only (disabled by default).

Changes:
- Add geoip_allow_http_fallback config flag (default False) to Settings
- Refactor GeoCache.lookup() and lookup_batch() to try MMDB first
- Update startup.py to pass config flag and log security warning when HTTP enabled
- Update all 49 tests to reflect new MMDB-primary strategy
- Add comprehensive geoip configuration section to Backend-Development.md
- Update Architekture.md to show MMDB + optional HTTP in system dependencies
- Update .env.example with BANGUI_GEOIP_DB_PATH and HTTP fallback flag

Security impact:
- 99% of IP addresses (successful MMDB lookups) now stay local, encrypted
- HTTP-only IPs are cached for 5 minutes to minimize external calls
- Operators must explicitly enable HTTP fallback (security-conscious default)
- GDPR/CCPA compliance: no PII sent over unencrypted networks by default

Fixes TASK-030: Resolved plaintext IP transmission to ip-api.com

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-26 15:31:39 +02:00
parent b9289a3b0e
commit 1d91e24a88
8 changed files with 313 additions and 135 deletions

View File

@@ -1,40 +1,3 @@
## TASK-029 — `Fail2BanConnectionError` leaks socket path in HTTP error responses
**Severity:** Medium
### Where found
`backend/app/exceptions.py``Fail2BanConnectionError.__init__()` formats the message as `f"{message} (socket: {socket_path})"`. `backend/app/main.py``_fail2ban_connection_handler()` returns `{"detail": f"Cannot reach fail2ban: {exc}"}` verbatim.
### Why this is needed
Every 502 response caused by fail2ban being unreachable includes the full socket path (e.g., `Cannot reach fail2ban: [Errno 2] No such file or directory (socket: /var/run/fail2ban/fail2ban.sock)`) in the JSON error body. This discloses internal infrastructure details to unauthenticated users who can trigger the error. Similarly, `_fail2ban_protocol_handler` includes raw exception details that may expose internal parsing logic.
### Goal
Return generic, user-friendly error messages in HTTP responses. Log full details server-side only.
### What to do
1. In `_fail2ban_connection_handler()`, replace:
```python
content={"detail": f"Cannot reach fail2ban: {exc}"}
```
with:
```python
content={"detail": "Cannot reach the fail2ban service. Check the server status page."}
```
2. In `_fail2ban_protocol_handler()`, similarly return a generic message.
3. Both handlers already log `error=str(exc)` server-side — this is correct and should remain.
### Possible traps and issues
- Update any tests that assert the exact `detail` string in 502 responses.
- If the frontend displays this error message directly to the user, ensure it still makes sense after genericizing.
### Docs changes needed
- `Backend-Development.md` — error message hygiene (no internal paths/details in responses).
### Doc references
- [Backend-Development.md](Backend-Development.md) — error handling
---
## TASK-030 — ip-api.com geo lookups use plain HTTP — IP addresses sent unencrypted
**Severity:** Medium