211 lines
5.1 KiB
Go
211 lines
5.1 KiB
Go
package render
|
|
|
|
import (
|
|
"github.com/peterqiu0516/sub-store/internal/model"
|
|
)
|
|
|
|
// RenderSurgeProxies renders proxies as Surge text lines.
|
|
func RenderSurgeProxies(proxies []model.ProxyNode) (string, error) {
|
|
return RenderTextProxyList(proxies, model.TargetSurge, func(p model.ProxyNode) string {
|
|
return ToSurgeProxyLine(p)
|
|
})
|
|
}
|
|
|
|
// RenderSurgeMacProxies renders proxies as Surge-Mac text lines (adds ssh/h2-connect/snell).
|
|
func RenderSurgeMacProxies(proxies []model.ProxyNode) (string, error) {
|
|
return RenderTextProxyList(proxies, model.TargetSurgeMac, func(p model.ProxyNode) string {
|
|
return ToSurgeMacProxyLine(p)
|
|
})
|
|
}
|
|
|
|
// ToSurgeProxyLine converts a single proxy node to a Surge proxy line.
|
|
// Returns "" for unsupported proxy types.
|
|
func ToSurgeProxyLine(proxy model.ProxyNode) string {
|
|
name := SanitizeTextProxyName(getString(proxy, "name"))
|
|
ptype := getString(proxy, "type")
|
|
server := getString(proxy, "server")
|
|
port := getInt(proxy, "port")
|
|
|
|
base := name + "=" + surgeType(proxy) + "," + server + "," + itoa(port)
|
|
entries := CommonTextOptions(proxy)
|
|
|
|
switch ptype {
|
|
case "ss":
|
|
entries = unshift(entries,
|
|
[2]any{"encrypt-method", strOr(proxy, "cipher", "none")},
|
|
[2]any{"password", proxy["password"]},
|
|
)
|
|
entries = AppendPluginOptions(entries, proxy, "surge")
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "vmess":
|
|
entries = unshift(entries,
|
|
[2]any{"username", proxy["uuid"]},
|
|
[2]any{"encrypt-method", strOr(proxy, "cipher", "auto")},
|
|
[2]any{"tls", proxy["tls"]},
|
|
[2]any{"sni", proxy["servername"]},
|
|
)
|
|
entries = AppendWsOptions(entries, proxy, "surge")
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "trojan":
|
|
entries = unshift(entries,
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"sni", sniOr(proxy, "sni", "servername")},
|
|
)
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "http", "socks5":
|
|
entries = unshift(entries,
|
|
[2]any{"username", proxy["username"]},
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"tls", proxy["tls"]},
|
|
[2]any{"sni", sniOr(proxy, "sni", "servername")},
|
|
)
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "hysteria2":
|
|
entries = unshift(entries,
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"sni", proxy["sni"]},
|
|
)
|
|
if obfs := proxy["obfs"]; obfs != nil {
|
|
entries = append(entries, [2]any{"obfs", obfs}, [2]any{"obfs-password", proxy["obfs-password"]})
|
|
}
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "tuic":
|
|
entries = unshift(entries,
|
|
[2]any{"uuid", proxy["uuid"]},
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"sni", proxy["sni"]},
|
|
)
|
|
return JoinTextProxy(name+"=tuic-v5,"+server+","+itoa(port), entries)
|
|
|
|
case "anytls":
|
|
entries = unshift(entries,
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"sni", sniOr(proxy, "sni", "servername")},
|
|
)
|
|
return JoinTextProxy(base, entries)
|
|
|
|
case "snell":
|
|
entries = unshift(entries,
|
|
[2]any{"psk", pskOrPassword(proxy)},
|
|
[2]any{"version", versionOr3(proxy)},
|
|
)
|
|
return JoinTextProxy(name+"=snell,"+server+","+itoa(port), entries)
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// ToSurgeMacProxyLine adds surge-mac specific types (ssh, h2-connect) on top
|
|
// of the base surge line.
|
|
func ToSurgeMacProxyLine(proxy model.ProxyNode) string {
|
|
name := SanitizeTextProxyName(getString(proxy, "name"))
|
|
ptype := getString(proxy, "type")
|
|
server := getString(proxy, "server")
|
|
port := getInt(proxy, "port")
|
|
|
|
switch ptype {
|
|
case "ssh":
|
|
entries := CommonTextOptions(proxy)
|
|
entries = unshift(entries,
|
|
[2]any{"username", proxy["username"]},
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"private-key", proxy["private-key"]},
|
|
)
|
|
return JoinTextProxy(name+"=ssh,"+server+","+itoa(port), entries)
|
|
|
|
case "h2-connect":
|
|
entries := CommonTextOptions(proxy)
|
|
entries = unshift(entries,
|
|
[2]any{"username", proxy["username"]},
|
|
[2]any{"password", proxy["password"]},
|
|
[2]any{"tls", proxy["tls"]},
|
|
[2]any{"sni", sniOr(proxy, "sni", "servername")},
|
|
)
|
|
return JoinTextProxy(name+"=h2-connect,"+server+","+itoa(port), entries)
|
|
}
|
|
|
|
return ToSurgeProxyLine(proxy)
|
|
}
|
|
|
|
func surgeType(proxy model.ProxyNode) string {
|
|
ptype := getString(proxy, "type")
|
|
if ptype == "socks5" {
|
|
if getBool(proxy, "tls") {
|
|
return "socks5-tls"
|
|
}
|
|
return "socks5"
|
|
}
|
|
if ptype == "http" {
|
|
if getBool(proxy, "tls") {
|
|
return "https"
|
|
}
|
|
return "http"
|
|
}
|
|
return ptype
|
|
}
|
|
|
|
// --- small helpers ---
|
|
|
|
func unshift(entries [][2]any, front ...[2]any) [][2]any {
|
|
return append(front, entries...)
|
|
}
|
|
|
|
func strOr(proxy model.ProxyNode, key, def string) string {
|
|
s := getString(proxy, key)
|
|
if s == "" {
|
|
return def
|
|
}
|
|
return s
|
|
}
|
|
|
|
func sniOr(proxy model.ProxyNode, keys ...string) any {
|
|
for _, k := range keys {
|
|
if v := proxy[k]; v != nil {
|
|
return v
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func pskOrPassword(proxy model.ProxyNode) any {
|
|
if v := proxy["psk"]; v != nil {
|
|
return v
|
|
}
|
|
return proxy["password"]
|
|
}
|
|
|
|
func versionOr3(proxy model.ProxyNode) any {
|
|
if v := proxy["version"]; v != nil {
|
|
return v
|
|
}
|
|
return 3
|
|
}
|
|
|
|
func itoa(n int) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
neg := false
|
|
if n < 0 {
|
|
neg = true
|
|
n = -n
|
|
}
|
|
var buf [20]byte
|
|
i := len(buf)
|
|
for n > 0 {
|
|
i--
|
|
buf[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
buf[i] = '-'
|
|
}
|
|
return string(buf[i:])
|
|
}
|