aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/api/netutil.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/api/netutil.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/api/netutil.py34
1 files changed, 34 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/netutil.py b/packages/meshbay-hub/src/meshbay_hub/api/netutil.py
new file mode 100644
index 0000000..aa8344a
--- /dev/null
+++ b/packages/meshbay-hub/src/meshbay_hub/api/netutil.py
@@ -0,0 +1,34 @@
+"""
+Client address resolution for the audit log and rate limiting.
+
+Finding M7: every call site did
+
+ fwd = request.headers.get("X-Forwarded-For")
+ return fwd.split(",")[0].strip() if fwd else request.client.host
+
+which trusts a header the client controls. Anyone could forge the IP written into
+the compliance log — the log that exists specifically to answer legal requests —
+and sidestep per-IP rate limiting at the same time.
+
+X-Forwarded-For is only consulted when the immediate peer is a trusted proxy, and
+then the *rightmost* entry is used: that is the one our own proxy appended, whereas
+the leftmost is whatever the client sent.
+"""
+
+from fastapi import Request
+
+# Caddy terminates TLS on the same host and proxies to 127.0.0.1:8000.
+TRUSTED_PROXIES = frozenset({"127.0.0.1", "::1", "localhost"})
+
+
+def client_ip(request: Request) -> str:
+ peer = request.client.host if request.client else ""
+
+ if peer in TRUSTED_PROXIES:
+ forwarded = request.headers.get("X-Forwarded-For")
+ if forwarded:
+ hops = [h.strip() for h in forwarded.split(",") if h.strip()]
+ if hops:
+ return hops[-1]
+
+ return peer or "unknown"