| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import json |
| import os |
| import time |
| import uuid |
| from http.server import SimpleHTTPRequestHandler, HTTPServer |
| from urllib.parse import urlparse |
| from pathlib import Path |
|
|
| ROOT = Path(__file__).parent.resolve() |
| STATIC_DIR = ROOT / "static" |
| PORT = int(os.environ.get("PORT", "7860")) |
| HOST = os.environ.get("HOST", "0.0.0.0") |
| SET_SECRET = os.environ.get("TOKEN_SET_SECRET") |
|
|
| storage = { |
| "token": None, |
| "updated_at": None, |
| } |
|
|
|
|
| def now_ms() -> int: |
| return int(time.time() * 1000) |
|
|
|
|
| class Handler(SimpleHTTPRequestHandler): |
| |
| def translate_path(self, path): |
| |
| parsed = urlparse(path) |
| p = parsed.path |
| if p == "/": |
| return str(STATIC_DIR / "token-service.html") |
| |
| safe = Path(p.lstrip("/")) |
| return str((STATIC_DIR / safe).resolve()) |
|
|
| |
| def _set_cors(self): |
| self.send_header("Access-Control-Allow-Origin", "*") |
| self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") |
| self.send_header("Access-Control-Allow-Headers", "*, Content-Type, X-Token-Set-Secret") |
| self.send_header("Access-Control-Max-Age", "600") |
|
|
| def _send_json(self, code: int, obj): |
| body = json.dumps(obj, ensure_ascii=False).encode("utf-8") |
| self.send_response(code) |
| self._set_cors() |
| self.send_header("Content-Type", "application/json; charset=utf-8") |
| self.send_header("Content-Length", str(len(body))) |
| self.end_headers() |
| self.wfile.write(body) |
|
|
| def do_OPTIONS(self): |
| if self.path.startswith("/api/"): |
| self.send_response(204) |
| self._set_cors() |
| self.end_headers() |
| else: |
| super().do_OPTIONS() |
|
|
| def do_GET(self): |
| if self.path.startswith("/api/"): |
| parsed = urlparse(self.path) |
| if parsed.path == "/api/token": |
| self._send_json(200, { |
| "token": storage["token"], |
| "nonce": str(uuid.uuid4()), |
| "updated_at": storage["updated_at"], |
| }) |
| return |
| if parsed.path == "/api/status": |
| self._send_json(200, { |
| "is_set": storage["token"] is not None, |
| "updated_at": storage["updated_at"], |
| }) |
| return |
| self._send_json(404, {"error": "not_found"}) |
| return |
| |
| return super().do_GET() |
|
|
| def do_POST(self): |
| if self.path.startswith("/api/"): |
| parsed = urlparse(self.path) |
| if parsed.path == "/api/set_token": |
| if SET_SECRET: |
| header_secret = self.headers.get("X-Token-Set-Secret") |
| if header_secret != SET_SECRET: |
| self._send_json(403, {"error": "forbidden"}) |
| return |
| try: |
| length = int(self.headers.get("Content-Length") or 0) |
| data = json.loads(self.rfile.read(length) or b"{}") |
| except Exception: |
| self._send_json(400, {"error": "invalid_json"}) |
| return |
| token = data.get("token") |
| if not token or not isinstance(token, str): |
| self._send_json(400, {"error": "missing_token"}) |
| return |
| storage["token"] = token |
| storage["updated_at"] = int(data.get("timestamp") or now_ms()) |
| print(f"[token-server] token set at {storage['updated_at']}") |
| self._send_json(200, {"success": True}) |
| return |
| self._send_json(404, {"error": "not_found"}) |
| return |
| |
| self.send_error(405, "Method Not Allowed") |
|
|
| |
| def log_message(self, fmt, *args): |
| if self.path.startswith("/api/"): |
| return |
| super().log_message(fmt, *args) |
|
|
|
|
| def main(): |
| |
| STATIC_DIR.mkdir(parents=True, exist_ok=True) |
| httpd = HTTPServer((HOST, PORT), Handler) |
| print(f"[hf-token-service] listening on http://{HOST}:{PORT}") |
| print(" - Static: / -> static/token-service.html") |
| print(" - API: /api/token, /api/status, /api/set_token") |
| try: |
| httpd.serve_forever() |
| except KeyboardInterrupt: |
| print("\n[hf-token-service] shutting down") |
|
|
|
|
| if __name__ == "__main__": |
| main() |
|
|
|
|