package httpapi import ( "net/http" "os" "path/filepath" "github.com/go-chi/chi/v5" ) // RulesHandler 静态服务国内分流(#5)用的 sing-box rule-set(.srs)文件。 // 客户端配置的 rule_set 指向 /v1/rules/{name},sing-box 直连下载 // (download_detour:direct);自托管避免 GitHub 在国内被墙的鸡生蛋问题。 // 只放行白名单文件名,防目录穿越。无需鉴权(sing-box 下载不带 token)。 type RulesHandler struct { dir string } // NewRulesHandler 指定 .srs 所在目录(PANGOLIN_RULES_DIR,默认 /var/lib/pangolin/rules)。 func NewRulesHandler(dir string) *RulesHandler { if dir == "" { dir = "/var/lib/pangolin/rules" } return &RulesHandler{dir: dir} } var allowedRuleSets = map[string]bool{ "geoip-cn.srs": true, "geosite-cn.srs": true, } // Serve 处理 GET /v1/rules/{name}。 func (h *RulesHandler) Serve(w http.ResponseWriter, r *http.Request) { name := chi.URLParam(r, "name") if !allowedRuleSets[name] { http.NotFound(w, r) return } f, err := os.Open(filepath.Join(h.dir, name)) if err != nil { http.NotFound(w, r) return } defer f.Close() st, err := f.Stat() if err != nil || st.IsDir() { http.NotFound(w, r) return } w.Header().Set("Content-Type", "application/octet-stream") http.ServeContent(w, r, name, st.ModTime(), f) }