📄 gost-panel-server.py 📝 编辑 ⬇ 下载 ← 返回列表
#!/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()