Hermes Agent commited on
Commit
8e7ea58
·
1 Parent(s): 1a13eed

Harden proxy.py: Add _strip_internal_ports for universal body/header port stripping + add /debug/status endpoint

Browse files
Files changed (1) hide show
  1. proxy.py +59 -9
proxy.py CHANGED
@@ -13,6 +13,35 @@ OMNIROUTE_PORT = 20128
13
  OPENCODE_PORT = 4097
14
  JELLYFIN_PORT = 8096
15
  TG_STREAM_PORT = 8080
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  client = httpx.AsyncClient(timeout=120.0, follow_redirects=False)
18
 
@@ -20,7 +49,7 @@ def get_headers(request: Request, extra_headers: dict = None):
20
  headers = dict(request.headers)
21
  headers.pop("host", None)
22
  headers.pop("content-length", None)
23
- headers["X-Forwarded-Host"] = "jishnupg-opencode-cli.hf.space"
24
  headers["X-Forwarded-Proto"] = "https"
25
  headers["X-Forwarded-Port"] = "443"
26
  if extra_headers:
@@ -50,11 +79,7 @@ async def proxy_http(target_url: str, request: Request, extra_headers: dict = No
50
  if lk in ["content-length", "transfer-encoding", "content-encoding"]:
51
  continue
52
  if lk == "location":
53
- v = re.sub(r"https?://[^/]+:4096/", "/", v)
54
- v = re.sub(r"https?://[^/]+:20128/", "/omniroute/", v)
55
- v = re.sub(r"https?://[^/]+:8098/", "/openwebui/", v)
56
- v = re.sub(r"https?://[^/]+:4097/", "/server/", v)
57
- v = re.sub(r"https?://[^/]+:8096/", "/jellyfin/", v)
58
  if v == "/login" or v.startswith("/login?"):
59
  v = "/omniroute" + v
60
  elif v == "/dashboard" or v.startswith("/dashboard?"):
@@ -64,11 +89,14 @@ async def proxy_http(target_url: str, request: Request, extra_headers: dict = No
64
  content = resp.content
65
  ctype = resp.headers.get("content-type", "")
66
 
67
- if sub_filters and ("text/html" in ctype or "javascript" in ctype or "json" in ctype):
 
68
  try:
69
  text_str = content.decode("utf-8", errors="ignore")
70
- for old_s, new_s in sub_filters:
71
- text_str = text_str.replace(old_s, new_s)
 
 
72
  content = text_str.encode("utf-8")
73
  except Exception:
74
  pass
@@ -128,6 +156,28 @@ async def root_hub():
128
  async def favicon():
129
  return Response(content=b"", status_code=204)
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  # ==========================================
132
  # 2. OPEN WEBUI ROUTES (/openwebui)
133
  # ==========================================
 
13
  OPENCODE_PORT = 4097
14
  JELLYFIN_PORT = 8096
15
  TG_STREAM_PORT = 8080
16
+ GATEWAY_PORT = 4096 # this proxy's own internal port — must NEVER appear in an outgoing URL
17
+
18
+ PUBLIC_HOST = "jishnupg-opencode-cli.hf.space"
19
+ PUBLIC_ORIGIN = f"https://{PUBLIC_HOST}"
20
+
21
+ # Every internal port -> the public path prefix it should be rewritten to.
22
+ PORT_TO_PREFIX = {
23
+ GATEWAY_PORT: "", # gateway's own port -> strip entirely (root-relative)
24
+ OMNIROUTE_PORT: "/omniroute",
25
+ WEBUI_PORT: "/openwebui",
26
+ OPENCODE_PORT: "/server",
27
+ JELLYFIN_PORT: "/jellyfin",
28
+ TG_STREAM_PORT: "/tg-stream",
29
+ }
30
+
31
+ # Matches http(s)://<any-host>:<any-known-internal-port>
32
+ _PORT_PATTERN = re.compile(
33
+ r"https?://[^/\s\"'>]+:(" + "|".join(str(p) for p in PORT_TO_PREFIX) + r")(?=/|\"|'|\s|$)"
34
+ )
35
+
36
+ def _strip_internal_ports(text: str) -> str:
37
+ """Rewrite any absolute URL pointing at one of our internal ports (on ANY
38
+ host — 127.0.0.1, localhost, or the public domain) into a root-relative,
39
+ correctly-prefixed path. This stops :4096 (or any internal port) from ever
40
+ reaching the browser."""
41
+ def _sub(m: "re.Match[str]") -> str:
42
+ port = int(m.group(1))
43
+ return PORT_TO_PREFIX.get(port, "")
44
+ return _PORT_PATTERN.sub(_sub, text)
45
 
46
  client = httpx.AsyncClient(timeout=120.0, follow_redirects=False)
47
 
 
49
  headers = dict(request.headers)
50
  headers.pop("host", None)
51
  headers.pop("content-length", None)
52
+ headers["X-Forwarded-Host"] = PUBLIC_HOST
53
  headers["X-Forwarded-Proto"] = "https"
54
  headers["X-Forwarded-Port"] = "443"
55
  if extra_headers:
 
79
  if lk in ["content-length", "transfer-encoding", "content-encoding"]:
80
  continue
81
  if lk == "location":
82
+ v = _strip_internal_ports(v)
 
 
 
 
83
  if v == "/login" or v.startswith("/login?"):
84
  v = "/omniroute" + v
85
  elif v == "/dashboard" or v.startswith("/dashboard?"):
 
89
  content = resp.content
90
  ctype = resp.headers.get("content-type", "")
91
 
92
+ is_textlike = any(t in ctype for t in ["text/html", "javascript", "json", "text/css", "text/plain"])
93
+ if is_textlike:
94
  try:
95
  text_str = content.decode("utf-8", errors="ignore")
96
+ if sub_filters:
97
+ for old_s, new_s in sub_filters:
98
+ text_str = text_str.replace(old_s, new_s)
99
+ text_str = _strip_internal_ports(text_str)
100
  content = text_str.encode("utf-8")
101
  except Exception:
102
  pass
 
156
  async def favicon():
157
  return Response(content=b"", status_code=204)
158
 
159
+ # ==========================================
160
+ # 1b. DEBUG STATUS ROUTE
161
+ # ==========================================
162
+ @app.api_route("/debug/status", methods=["GET"])
163
+ async def debug_status():
164
+ """Hits each internal service directly on 127.0.0.1 and reports status."""
165
+ checks = {
166
+ "opencode_server": f"http://127.0.0.1:{OPENCODE_PORT}/",
167
+ "omniroute": f"http://127.0.0.1:{OMNIROUTE_PORT}/",
168
+ "open_webui": f"http://127.0.0.1:{WEBUI_PORT}/",
169
+ "jellyfin": f"http://127.0.0.1:{JELLYFIN_PORT}/",
170
+ "tg_streamer": f"http://127.0.0.1:{TG_STREAM_PORT}/",
171
+ }
172
+ results = {}
173
+ for name, url in checks.items():
174
+ try:
175
+ r = await client.get(url, timeout=5.0)
176
+ results[name] = {"status": "up", "http_status": r.status_code}
177
+ except Exception as e:
178
+ results[name] = {"status": "down", "error": str(e)}
179
+ return results
180
+
181
  # ==========================================
182
  # 2. OPEN WEBUI ROUTES (/openwebui)
183
  # ==========================================