#!/usr/bin/env python3 """ Same-origin preview proxy for the testdatadb front-end. Serves the static prototype from ROOT and reverse-proxies /api/* to the live AD2 testdatadb server, so the app AND the cert iframe share one origin (http://127.0.0.1:PORT). That lets the same-origin-only cert styling/fit logic (styleCert/fitCert read iframe.contentDocument) actually run during preview — which it can't when the iframe is loaded cross-origin straight from AD2. Usage: python preview-proxy.py [target] """ import http.server, socketserver, urllib.request, urllib.error, os, sys PORT = int(sys.argv[1]) ROOT = os.path.abspath(sys.argv[2]) if len(sys.argv) > 2 else "." TARGET = sys.argv[3] if len(sys.argv) > 3 else "http://192.168.0.6:3000" class H(http.server.BaseHTTPRequestHandler): def do_GET(self): if self.path.startswith("/api/"): try: with urllib.request.urlopen(TARGET + self.path, timeout=30) as r: body = r.read(); ct = r.headers.get("Content-Type", "application/octet-stream") self._send(200, ct, body) except urllib.error.HTTPError as e: self._send(e.code, "application/json", e.read()) except Exception as e: self._send(502, "text/plain", str(e).encode()) else: p = self.path.split("?")[0] p = "/index.html" if p == "/" else p fp = os.path.join(ROOT, p.lstrip("/")) if os.path.isfile(fp): ct = "text/html; charset=utf-8" if fp.endswith(".html") else "application/octet-stream" self._send(200, ct, open(fp, "rb").read()) else: self._send(404, "text/plain", b"not found") def do_POST(self): if self.path.startswith("/api/"): n = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(n) if n else b"" req = urllib.request.Request( TARGET + self.path, data=body, method="POST", headers={"Content-Type": self.headers.get("Content-Type", "application/json")}) try: with urllib.request.urlopen(req, timeout=120) as r: self._send(200, r.headers.get("Content-Type", "application/json"), r.read()) except urllib.error.HTTPError as e: self._send(e.code, "application/json", e.read()) except Exception as e: self._send(502, "text/plain", str(e).encode()) else: self._send(404, "text/plain", b"not found") def _send(self, code, ct, body): self.send_response(code) self.send_header("Content-Type", ct) self.send_header("Content-Length", str(len(body))) self.send_header("Cache-Control", "no-store") self.end_headers() self.wfile.write(body) def log_message(self, *a): pass class S(socketserver.ThreadingTCPServer): allow_reuse_address = True print(f"preview proxy: http://127.0.0.1:{PORT} root={ROOT} -> {TARGET}") S(("127.0.0.1", PORT), H).serve_forever()