feat: replace inline IP resolution with centralized client_ip utility across routers and audit

Consolidate scattered `X-Real-IP` / `request.client.host` fallback logic into the single `client_ip()` helper from `utils`, reducing duplication in the rate limiter middleware, project file zip routes, tools shared module, and audit record builder. Also refactor three admin endpoints (`/ai-usage/data`, `/analytics`, `/users/{uid}/ai-usage`) to use the existing `require_admin()` guard instead of repeating manual auth checks, and remove now-unused `get_current_user`/`is_admin` imports from those modules.
This commit is contained in:
2026-07-04 18:07:33 +00:00
parent 244a524b91
commit 3fbac87723
14 changed files with 266 additions and 36 deletions
+10
View File
@@ -923,6 +923,16 @@ Then enable **Container builds** and **Containers** on `/admin/services`. Builds
- **Upload size:** `NGINX_MAX_BODY_SIZE` (default `50m`) must be **>= the admin-configurable `max_upload_size_mb`** (Admin -> Settings), or large uploads are rejected with HTTP 413 before reaching the app.
- **Micro-cache:** off by default; enable with `NGINX_CACHE_ENABLED=true`.
### Client IP behind a proxy
The app resolves the real client address via `utils.client_ip(request)`, which reads `X-Real-IP` first, then the leftmost hop of `X-Forwarded-For`, then falls back to `request.client.host`. This is the single source used by the rate limiter, the audit log (`actor_ip`), and guest-scoped job ownership, so every logged IP is the actual visitor rather than the proxy loopback. The bundled nginx config already sets both headers on every location. When fronting the app with **Caddy**, `X-Forwarded-For` is set automatically, but `X-Real-IP` is not; add an unspoofable real-IP header inside the `reverse_proxy` block for the strongest attribution:
```
reverse_proxy localhost:10500 {
header_up X-Real-IP {remote_host}
}
```
### Static asset caching
Static assets (CSS, JS, vendored libraries) are served with a **one-year immutable cache** for the best Lighthouse "efficient cache policy" score, while deploys still take effect immediately. Every app-owned static URL carries a boot-time version path segment, `/static/v<timestamp>/...`, where `<timestamp>` is the unix time the server process started (`config.STATIC_VERSION`). A restart changes the segment, so every asset URL changes and returning browsers refetch on their next page load - no cache purge, no hashing build step.