package common import ( "context" "encoding/json" "fmt" "io" "net" "net/http" "os" "strings" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" ) const UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36" func LoadCookies(path string) (string, error) { data, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("cannot read cookies: %w", err) } var cookies []struct { Name string `json:"name"` Value string `json:"value"` } if err := json.Unmarshal(data, &cookies); err != nil { return "", fmt.Errorf("cannot parse cookies: %w", err) } parts := make([]string, len(cookies)) for i, c := range cookies { parts[i] = c.Name + "=" + c.Value } return strings.Join(parts, "; "), nil } func HttpClient(dialer N.Dialer) *http.Client { return &http.Client{ Transport: &http.Transport{ DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) }, }, } } func HttpGet(dialer N.Dialer, endpoint string) ([]byte, error) { req, _ := http.NewRequest("GET", endpoint, nil) req.Header.Set("User-Agent", UserAgent) resp, err := HttpClient(dialer).Do(req) if err != nil { return nil, err } defer resp.Body.Close() return io.ReadAll(resp.Body) } func CookieValue(cookieHeader, name string) string { for _, part := range strings.Split(cookieHeader, ";") { part = strings.TrimSpace(part) eq := strings.IndexByte(part, '=') if eq != -1 && part[:eq] == name { return part[eq+1:] } } return "" } func FilterCookies(cookieHeader string, allow []string) string { allowed := make(map[string]struct{}, len(allow)) for _, n := range allow { allowed[n] = struct{}{} } var out []string for _, part := range strings.Split(cookieHeader, ";") { trimmed := strings.TrimSpace(part) eq := strings.IndexByte(trimmed, '=') if eq == -1 { continue } if _, ok := allowed[trimmed[:eq]]; ok { out = append(out, trimmed) } } return strings.Join(out, "; ") }