package config import "strings" // DetectProtocol infers protocol from a share/proxy URI or config body. func DetectProtocol(raw string) Protocol { raw = stripShareNoise(raw) lower := strings.ToLower(strings.TrimSpace(raw)) switch { case strings.HasPrefix(lower, "hysteria2://"), strings.HasPrefix(lower, "hy2://"): return ProtocolHysteria2 case strings.HasPrefix(lower, "vless://"): return ProtocolVLESS case strings.HasPrefix(lower, "vmess://"): return ProtocolVMess case strings.HasPrefix(lower, "trojan://"): return ProtocolTrojan case strings.HasPrefix(lower, "awg://"), strings.HasPrefix(lower, "amneziawg://"), strings.HasPrefix(lower, "wireguard://"), strings.HasPrefix(lower, "vpn://"): return ProtocolAWG case strings.Contains(lower, "[interface]") && (strings.Contains(lower, "privatekey") || strings.Contains(lower, "private_key") || strings.Contains(lower, "private key")): return ProtocolAWG case strings.HasPrefix(strings.TrimSpace(raw), "{") && (strings.Contains(lower, "client_priv_key") || strings.Contains(lower, "server_pub_key")): return ProtocolAWG case strings.HasPrefix(lower, "naive+"), strings.HasPrefix(lower, "naive://"), strings.HasPrefix(lower, "https://"), strings.HasPrefix(lower, "quic://"), strings.HasPrefix(lower, "http://"): return ProtocolNaive default: return "" } } func stripShareNoise(raw string) string { raw = strings.TrimPrefix(raw, "\ufeff") var b strings.Builder for _, r := range raw { switch r { case '\u200b', '\u200c', '\u200d', '\u2060', '\ufeff', '\u2066', '\u2067', '\u2068', '\u2069', '\u200e', '\u200f', '\u202a', '\u202b', '\u202c', '\u202d', '\u202e': continue } if r < 0x20 && r != '\n' && r != '\r' && r != '\t' { continue } b.WriteRune(r) } return strings.TrimSpace(b.String()) }