#!/usr/bin/env python3 http.server BaseHTTPRequestHandler, HTTPServer urllib.request, urllib.error, os PANEL_FILE="/opt/gostpanel/panel.html" SERVER_IP="." : urllib.request _u _src ("http://members.org/dyndns/getip","http://ip.net","https://api.ipify.org"): : v=_u.urlopen(_src,timeout=).read().decode().strip() v: SERVER_IP=v; Exception: Exception: SERVER_IP SERVER_IP==".": : socket _s _sk=_s.socket(_s.AF_INET,_s.SOCK_DGRAM) _sk.connect((".",)) SERVER_IP=_sk.getsockname()[]; _sk.close() Exception: # 动态读取 gost API/SAVE 端口(启动时和每次代理时兜底) re _re _read_api_ports(): api, save = "", "" : open("/etc/gost/gost.yaml") f: txt = f.read() m = _re.search(r"^api:\s*\n\s*addr:\s*:?(\d+)", txt, _re.M) m: api = m.group() # save端口: gost-save-server.py监听(SAVE_PORT写在文件里)或默认18081 m2 = _re.search(r"HTTPServer\(\(\"\.\.\.\",(\d+)\)", open("/usr/local/bin/gost-save-server.py").read()) m2: save = m2.group() Exception: api, save GOST_API_PORT, GOST_SAVE_PORT = _read_api_ports() H(BaseHTTPRequestHandler): _apiconfig(self): json J, os CFG="/opt/gostpanel/apiconfig.json" # 认证: Basic 或 同源(GET可以同源不认证? 配置含密码 — 必须认证) # GET免认证(同源面板场景); POST仍需认证(写操作保护) self.command=="POST": auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): base64 : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); self.command=="GET": : open(CFG) f: body=f.read().encode() Exception: body=b"[]" self.send_response() self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.send_header("Content-Length",str(len(body))) self.end_headers(); self.wfile.write(body); self.command=="POST": n=int(self.headers.get("Content-Length","") ) data=self.rfile.read(n) : arr=J.loads(data) assert isinstance(arr,list) os.makedirs(os.path.dirname(CFG),exist_ok=) open(CFG,"w") f: f.write(J.dumps(arr,ensure_ascii=,indent=)) r=J.dumps({"ok":}).encode() self.send_response() Exception e: r=J.dumps({"ok":,"err":str(e)}).encode() self.send_response() self.send_header("Content-Type","application/json") self.send_header("Content-Length",str(len(r))) self.end_headers(); self.wfile.write(r); self.send_response(); self.end_headers(); _status(self): subprocess, time, json J, base64 auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); : active=subprocess.run(["systemctl","is-active","gost"],capture_output=,text=).stdout.strip() ver=subprocess.run(["/usr/local/bin/gost","-V"],capture_output=,text=).stdout.strip() since=subprocess.run(["systemctl","show","gost","-p","ActiveEnterTimestamp","--value"],capture_output=,text=).stdout.strip() Exception e: active="unknown"; ver=""; since=str(e) ver=subprocess.run(["/usr/local/bin/gost","-V"],capture_output=,text=).stdout.strip() since=subprocess.run(["systemctl","show","gost","-p","ActiveEnterTimestamp","--value"],capture_output=,text=).stdout.strip() uptime="" : out=subprocess.run(["systemctl","show","gost","-p","ActiveEnterTimestampMonotonic","--value"],capture_output=,text=).stdout.strip() Exception: r=J.dumps({"active":active,"version":ver,"since":since}).encode() self.send_response() self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.end_headers(); self.wfile.write(r) _checkport(self): socket, base64 auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); json J n=int(self.headers.get("Content-Length","") ) : data=J.loads(self.rfile.read(n)); port=int(data.get("port",)) Exception: port= occupied= port>: s=socket.socket(); s.settimeout() : s.bind((".",port)); s.close() Exception: occupied= out=J.dumps({"port":port,"occupied":occupied}).encode() self.send_response() self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.end_headers(); self.wfile.write(out) _pingtest(self): socket, base64, json J, time auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); n=int(self.headers.get("Content-Length","") ) target="" : data=J.loads(self.rfile.read(n)); target=data.get("target","") Exception: result={"target":target,"ok":,"ms":,"err":""} : host,port=target.rsplit(":",); port=int(port) s=socket.socket(); s.settimeout() t0=time.time(); s.connect((host,port)); result["ms"]=round((time.time()-t0)*) s.close(); result["ok"]= Exception e: result["err"]=str(e)[:] r=J.dumps(result).encode() self.send_response() self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.end_headers(); self.wfile.write(r) _logop(self): base64, json J, datetime auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); n=int(self.headers.get("Content-Length","") ) : data=J.loads(self.rfile.read(n)) line=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+" "+data.get("action","")+" "+data.get("detail","")+"\n" open("/opt/gostpanel/oplog.log","a") f: f.write(line) Exception: self.send_response(); self.end_headers() _getlog(self): base64, json J auth=self.headers.get("Authorization","") USER="admin"; PASS="oyh159159oiw.@" ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u==USER pw==PASS) Exception: ok= ok: self.send_response(); self.end_headers(); : open("/opt/gostpanel/oplog.log") f: lines=f.readlines()[-:] r=J.dumps({"log":" vas ".join([]) "".join(lines[-:])}).encode() FileNotFoundError: r=b'{"log":""}' Exception e: r=J.dumps({"log":"读取失败: "+str(e)}).encode() self.send_response() self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.end_headers(); self.wfile.write(r) _proxy(self): p=self.path p=="/status": self._status(); p=="/apiconfig": self._apiconfig(); p=="/checkport": self._checkport(); p=="/pingtest": self._pingtest(); p=="/logop": self._logop(); p=="/getlog": self._getlog(); p.startswith("/gostapi"): t="http://.:"+GOST_API_PORT+p p.startswith("/save"): t="http://.:"+GOST_SAVE_PORT+p p.startswith("/yaml"): t="http://.:"+GOST_SAVE_PORT+p p.startswith("/rawyaml"): t="http://.:"+GOST_SAVE_PORT+p p=="/restart": t= : auth=self.headers.get("Authorization","") t is : base64, subprocess ok= auth.startswith("Basic "): : u,pw=base64.b64decode(auth[:]).decode().split(":",) ok=(u=="admin" pw=="oyh159159oiw.@") Exception: ok= ok: self.send_response(); self.end_headers(); r=subprocess.run(["systemctl","restart","gost"],capture_output=,timeout=) msg=b"OK: gost restarted" r.returncode== b"FAIL" self.send_response( r.returncode== ) self.send_header("Access-Control-Allow-Origin","*") self.send_header("Content-Type","text/plain") self.end_headers(); self.wfile.write(msg); : n=int(self.headers.get("Content-Length","") ) body=self.rfile.read(n) n req=urllib.request.Request(t,data=body,method=self.command) auth: req.add_header("Authorization",auth) body: req.add_header("Content-Type","application/json") : urllib.request.urlopen(req,timeout=) r: cl=r.headers.get("Content-Length") data=r.read(int(cl)) cl r.read(); code=r.status urllib.error.HTTPError he: cl=he.headers.get("Content-Length") data=he.read(int(cl)) cl he.read() b"" code=he.code Exception e: data=str(e).encode(); code= self.send_response(code) self.send_header("Content-Type","application/json") self.send_header("Access-Control-Allow-Origin","*") self.send_header("Access-Control-Allow-Headers","*") self.send_header("Access-Control-Allow-Methods","GET,POST,DELETE,PUT,OPTIONS") self.end_headers(); self.wfile.write(data) do_GET(self): self.path=="/serverip": self.send_response() self.send_header("Content-Type","text/plain") self.send_header("Access-Control-Allow-Origin","*") self.end_headers(); self.wfile.write(SERVER_IP.encode()); self._proxy(): : open(PANEL_FILE,"rb") f: body=f.read() self.send_response() self.send_header("Content-Type","text/html; charset=utf-") self.send_header("Content-Length",str(len(body))) self.send_header("Cache-Control","no-cache, no-store, must-revalidate") self.send_header("Pragma","no-cache") self.end_headers(); self.wfile.write(body) Exception e: self.send_response(); self.end_headers(); self.wfile.write(str(e).encode()) do_POST(self): self._proxy() do_DELETE(self): self._proxy() do_PUT(self): self._proxy() do_OPTIONS(self): self.send_response() self.send_header("Access-Control-Allow-Origin","*") self.send_header("Access-Control-Allow-Headers","*") self.send_header("Access-Control-Allow-Methods","GET,POST,DELETE,PUT,OPTIONS") self.end_headers() log_message(self,*a): HTTPServer((".",),H).serve_forever()