持续集成修复订阅错误的问题
This commit is contained in:
@@ -104,6 +104,9 @@ func buildClashProxy(templateName string, conf service.NodeServerConfig, passwor
|
||||
switch toClashInt(conf.Tls) {
|
||||
case 1:
|
||||
proxy["tls"] = true
|
||||
if fp := tlsFingerprint(conf.UTLS); fp != "" {
|
||||
proxy["client-fingerprint"] = fp
|
||||
}
|
||||
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||
proxy["skip-cert-verify"] = toClashBool(tlsSettings["allow_insecure"])
|
||||
if serverName := toClashString(tlsSettings["server_name"]); serverName != "" {
|
||||
@@ -112,6 +115,9 @@ func buildClashProxy(templateName string, conf service.NodeServerConfig, passwor
|
||||
}
|
||||
case 2:
|
||||
proxy["tls"] = true
|
||||
if fp := tlsFingerprint(conf.UTLS); fp != "" {
|
||||
proxy["client-fingerprint"] = fp
|
||||
}
|
||||
if tlsSettings, ok := conf.TlsSettings.(map[string]any); ok {
|
||||
proxy["skip-cert-verify"] = toClashBool(tlsSettings["allow_insecure"])
|
||||
if serverName := toClashString(tlsSettings["server_name"]); serverName != "" {
|
||||
@@ -123,11 +129,83 @@ func buildClashProxy(templateName string, conf service.NodeServerConfig, passwor
|
||||
}
|
||||
}
|
||||
}
|
||||
network := toClashString(conf.Network)
|
||||
if network == "" {
|
||||
network = "tcp"
|
||||
proxy["network"] = "tcp"
|
||||
if settings, ok := conf.NetworkSettings.(map[string]any); ok {
|
||||
switch toClashString(conf.Network) {
|
||||
case "", "tcp":
|
||||
if header, ok := settings["header"].(map[string]any); ok && toClashString(header["type"]) == "http" {
|
||||
proxy["network"] = "http"
|
||||
httpOpts := map[string]any{}
|
||||
if request, ok := header["request"].(map[string]any); ok {
|
||||
if headers, ok := request["headers"].(map[string]any); ok && len(headers) > 0 {
|
||||
httpOpts["headers"] = headers
|
||||
}
|
||||
if paths := clashPathList(request["path"]); len(paths) > 0 {
|
||||
httpOpts["path"] = paths
|
||||
}
|
||||
}
|
||||
if len(httpOpts) > 0 {
|
||||
proxy["http-opts"] = httpOpts
|
||||
}
|
||||
}
|
||||
case "ws":
|
||||
proxy["network"] = "ws"
|
||||
wsOpts := map[string]any{}
|
||||
if path := toClashString(settings["path"]); path != "" {
|
||||
wsOpts["path"] = path
|
||||
}
|
||||
if headers, ok := settings["headers"].(map[string]any); ok {
|
||||
if host := toClashString(headers["Host"]); host != "" {
|
||||
wsOpts["headers"] = map[string]any{"Host": host}
|
||||
}
|
||||
}
|
||||
if len(wsOpts) > 0 {
|
||||
proxy["ws-opts"] = wsOpts
|
||||
}
|
||||
case "grpc":
|
||||
proxy["network"] = "grpc"
|
||||
if serviceName := toClashString(settings["serviceName"]); serviceName != "" {
|
||||
proxy["grpc-opts"] = map[string]any{"grpc-service-name": serviceName}
|
||||
}
|
||||
case "h2":
|
||||
proxy["network"] = "h2"
|
||||
h2Opts := map[string]any{}
|
||||
if path := toClashString(settings["path"]); path != "" {
|
||||
h2Opts["path"] = path
|
||||
}
|
||||
if hosts := clashHostList(settings["host"]); len(hosts) > 0 {
|
||||
h2Opts["host"] = hosts
|
||||
}
|
||||
if len(h2Opts) > 0 {
|
||||
proxy["h2-opts"] = h2Opts
|
||||
}
|
||||
case "httpupgrade":
|
||||
proxy["network"] = "ws"
|
||||
wsOpts := map[string]any{
|
||||
"v2ray-http-upgrade": true,
|
||||
}
|
||||
if path := toClashString(settings["path"]); path != "" {
|
||||
wsOpts["path"] = path
|
||||
}
|
||||
host := toClashString(settings["host"])
|
||||
if host == "" {
|
||||
host = conf.RawHost
|
||||
}
|
||||
if host != "" {
|
||||
wsOpts["headers"] = map[string]any{"Host": host}
|
||||
}
|
||||
proxy["ws-opts"] = wsOpts
|
||||
default:
|
||||
if network := toClashString(conf.Network); network != "" {
|
||||
proxy["network"] = network
|
||||
}
|
||||
}
|
||||
} else if network := toClashString(conf.Network); network != "" {
|
||||
proxy["network"] = network
|
||||
}
|
||||
if smux := buildClashSmux(conf.Multiplex); smux != nil {
|
||||
proxy["smux"] = smux
|
||||
}
|
||||
proxy["network"] = network
|
||||
return proxy
|
||||
case "trojan":
|
||||
return map[string]any{
|
||||
@@ -208,6 +286,80 @@ func appendUniqueAny(base []any, values ...any) []any {
|
||||
return base
|
||||
}
|
||||
|
||||
func clashPathList(value any) []string {
|
||||
switch typed := value.(type) {
|
||||
case []string:
|
||||
return append([]string{}, typed...)
|
||||
case []any:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
text := toClashString(item)
|
||||
if text != "" {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
return result
|
||||
case string:
|
||||
if typed == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{typed}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func clashHostList(value any) []string {
|
||||
switch typed := value.(type) {
|
||||
case []string:
|
||||
return append([]string{}, typed...)
|
||||
case []any:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
text := toClashString(item)
|
||||
if text != "" {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
return result
|
||||
case string:
|
||||
if typed == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{typed}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func buildClashSmux(value any) map[string]any {
|
||||
settings, ok := value.(map[string]any)
|
||||
if !ok || !toClashBool(settings["enabled"]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
smux := map[string]any{
|
||||
"enabled": true,
|
||||
}
|
||||
if protocol := toClashString(settings["protocol"]); protocol != "" {
|
||||
smux["protocol"] = protocol
|
||||
}
|
||||
if maxConnections := toClashInt(settings["max_connections"]); maxConnections > 0 {
|
||||
smux["max-connections"] = maxConnections
|
||||
}
|
||||
if toClashBool(settings["padding"]) {
|
||||
smux["padding"] = true
|
||||
}
|
||||
if brutal, ok := settings["brutal"].(map[string]any); ok && toClashBool(brutal["enabled"]) {
|
||||
smux["brutal-opts"] = map[string]any{
|
||||
"enabled": true,
|
||||
"up": toClashInt(brutal["up_mbps"]),
|
||||
"down": toClashInt(brutal["down_mbps"]),
|
||||
}
|
||||
}
|
||||
return smux
|
||||
}
|
||||
|
||||
func toClashString(value any) string {
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
|
||||
@@ -107,6 +107,7 @@ func buildVmess(c service.NodeServerConfig, password string) string {
|
||||
|
||||
func buildVless(c service.NodeServerConfig, password string) string {
|
||||
params := url.Values{}
|
||||
params.Set("mode", "multi")
|
||||
params.Set("encryption", "none")
|
||||
if c.Flow != nil {
|
||||
params.Set("flow", toString(c.Flow))
|
||||
@@ -116,18 +117,26 @@ func buildVless(c service.NodeServerConfig, password string) string {
|
||||
switch toInt(c.Tls) {
|
||||
case 1:
|
||||
security = "tls"
|
||||
if fp := tlsFingerprint(c.UTLS); fp != "" {
|
||||
params.Set("fp", fp)
|
||||
}
|
||||
if tlsSettings, ok := c.TlsSettings.(map[string]any); ok {
|
||||
params.Set("sni", toString(tlsSettings["server_name"]))
|
||||
if toString(tlsSettings["allow_insecure"]) == "1" {
|
||||
if truthy(tlsSettings["allow_insecure"]) {
|
||||
params.Set("allowInsecure", "1")
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
security = "reality"
|
||||
if fp := tlsFingerprint(c.UTLS); fp != "" {
|
||||
params.Set("fp", fp)
|
||||
}
|
||||
if tlsSettings, ok := c.TlsSettings.(map[string]any); ok {
|
||||
params.Set("pbk", toString(tlsSettings["public_key"]))
|
||||
params.Set("sid", toString(tlsSettings["short_id"]))
|
||||
params.Set("sni", toString(tlsSettings["server_name"]))
|
||||
params.Set("servername", toString(tlsSettings["server_name"]))
|
||||
params.Set("spx", "/")
|
||||
}
|
||||
}
|
||||
params.Set("security", security)
|
||||
@@ -142,6 +151,19 @@ func buildVless(c service.NodeServerConfig, password string) string {
|
||||
}
|
||||
case "grpc":
|
||||
params.Set("serviceName", toString(settings["serviceName"]))
|
||||
case "h2":
|
||||
params.Set("type", "http")
|
||||
params.Set("path", toString(settings["path"]))
|
||||
if host := joinConfigValue(settings["host"]); host != "" {
|
||||
params.Set("host", host)
|
||||
}
|
||||
case "httpupgrade":
|
||||
params.Set("path", toString(settings["path"]))
|
||||
host := toString(settings["host"])
|
||||
if host == "" {
|
||||
host = c.RawHost
|
||||
}
|
||||
params.Set("host", host)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,6 +266,34 @@ func wrapIPv6(host string) string {
|
||||
return host
|
||||
}
|
||||
|
||||
func tlsFingerprint(value any) string {
|
||||
settings, ok := value.(map[string]any)
|
||||
if !ok || !truthy(settings["enabled"]) {
|
||||
return ""
|
||||
}
|
||||
return toString(settings["fingerprint"])
|
||||
}
|
||||
|
||||
func joinConfigValue(value any) string {
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
return typed
|
||||
case []string:
|
||||
return strings.Join(typed, ",")
|
||||
case []any:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
text := toString(item)
|
||||
if text != "" {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
return strings.Join(result, ",")
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func toString(v any) string {
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
@@ -265,3 +315,22 @@ func toInt(v any) int {
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func truthy(v any) bool {
|
||||
switch typed := v.(type) {
|
||||
case bool:
|
||||
return typed
|
||||
case int:
|
||||
return typed != 0
|
||||
case int64:
|
||||
return typed != 0
|
||||
case float64:
|
||||
return typed != 0
|
||||
case string:
|
||||
switch strings.ToLower(strings.TrimSpace(typed)) {
|
||||
case "1", "true", "yes", "on":
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -89,6 +89,9 @@ func buildSingBoxOutbound(conf service.NodeServerConfig, password string) map[st
|
||||
if transport := buildSingBoxTransport(conf); transport != nil {
|
||||
outbound["transport"] = transport
|
||||
}
|
||||
if multiplex := buildSingBoxMultiplex(conf.Multiplex); multiplex != nil {
|
||||
outbound["multiplex"] = multiplex
|
||||
}
|
||||
case "trojan":
|
||||
outbound["type"] = "trojan"
|
||||
outbound["password"] = password
|
||||
@@ -134,6 +137,9 @@ func generateSingBoxFallback(servers []model.Server, user model.User) (string, e
|
||||
if transport := buildSingBoxTransport(conf); transport != nil {
|
||||
outbound["transport"] = transport
|
||||
}
|
||||
if multiplex := buildSingBoxMultiplex(conf.Multiplex); multiplex != nil {
|
||||
outbound["multiplex"] = multiplex
|
||||
}
|
||||
case "trojan":
|
||||
outbound["type"] = "trojan"
|
||||
outbound["password"] = password
|
||||
@@ -161,6 +167,7 @@ func generateSingBoxFallback(servers []model.Server, user model.User) (string, e
|
||||
}
|
||||
|
||||
func buildSingBoxTLS(conf service.NodeServerConfig) map[string]any {
|
||||
utlsConfig := buildSingBoxUTLS(conf.UTLS)
|
||||
switch singBoxInt(conf.Tls) {
|
||||
case 1:
|
||||
tls := map[string]any{
|
||||
@@ -172,6 +179,9 @@ func buildSingBoxTLS(conf service.NodeServerConfig) map[string]any {
|
||||
tls["server_name"] = serverName
|
||||
}
|
||||
}
|
||||
if utlsConfig != nil {
|
||||
tls["utls"] = utlsConfig
|
||||
}
|
||||
return tls
|
||||
case 2:
|
||||
tls := map[string]any{
|
||||
@@ -188,6 +198,9 @@ func buildSingBoxTLS(conf service.NodeServerConfig) map[string]any {
|
||||
"short_id": singBoxString(tlsSettings["short_id"]),
|
||||
}
|
||||
}
|
||||
if utlsConfig != nil {
|
||||
tls["utls"] = utlsConfig
|
||||
}
|
||||
return tls
|
||||
default:
|
||||
return nil
|
||||
@@ -223,6 +236,19 @@ func buildSingBoxTransport(conf service.NodeServerConfig) map[string]any {
|
||||
}
|
||||
}
|
||||
return transport
|
||||
case "h2":
|
||||
transport := map[string]any{
|
||||
"type": "http",
|
||||
}
|
||||
if settings != nil {
|
||||
if path := singBoxString(settings["path"]); path != "" {
|
||||
transport["path"] = path
|
||||
}
|
||||
if host := singBoxHostValue(settings["host"]); len(host) > 0 {
|
||||
transport["host"] = host
|
||||
}
|
||||
}
|
||||
return transport
|
||||
case "httpupgrade":
|
||||
transport := map[string]any{
|
||||
"type": "httpupgrade",
|
||||
@@ -239,6 +265,81 @@ func buildSingBoxTransport(conf service.NodeServerConfig) map[string]any {
|
||||
}
|
||||
}
|
||||
return transport
|
||||
case "quic":
|
||||
return map[string]any{
|
||||
"type": "quic",
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func buildSingBoxUTLS(value any) map[string]any {
|
||||
settings, ok := value.(map[string]any)
|
||||
if !ok || !singBoxBool(settings["enabled"]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
utls := map[string]any{
|
||||
"enabled": true,
|
||||
}
|
||||
if fingerprint := singBoxString(settings["fingerprint"]); fingerprint != "" {
|
||||
utls["fingerprint"] = fingerprint
|
||||
}
|
||||
return utls
|
||||
}
|
||||
|
||||
func buildSingBoxMultiplex(value any) map[string]any {
|
||||
settings, ok := value.(map[string]any)
|
||||
if !ok || !singBoxBool(settings["enabled"]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
multiplex := map[string]any{
|
||||
"enabled": true,
|
||||
}
|
||||
if protocol := singBoxString(settings["protocol"]); protocol != "" {
|
||||
multiplex["protocol"] = protocol
|
||||
}
|
||||
if maxConnections := singBoxInt(settings["max_connections"]); maxConnections > 0 {
|
||||
multiplex["max_connections"] = maxConnections
|
||||
}
|
||||
if minStreams := singBoxInt(settings["min_streams"]); minStreams > 0 {
|
||||
multiplex["min_streams"] = minStreams
|
||||
}
|
||||
if maxStreams := singBoxInt(settings["max_streams"]); maxStreams > 0 {
|
||||
multiplex["max_streams"] = maxStreams
|
||||
}
|
||||
if singBoxBool(settings["padding"]) {
|
||||
multiplex["padding"] = true
|
||||
}
|
||||
if brutal, ok := settings["brutal"].(map[string]any); ok && singBoxBool(brutal["enabled"]) {
|
||||
multiplex["brutal"] = map[string]any{
|
||||
"enabled": true,
|
||||
"up_mbps": singBoxInt(brutal["up_mbps"]),
|
||||
"down_mbps": singBoxInt(brutal["down_mbps"]),
|
||||
}
|
||||
}
|
||||
return multiplex
|
||||
}
|
||||
|
||||
func singBoxHostValue(value any) []string {
|
||||
switch typed := value.(type) {
|
||||
case string:
|
||||
if typed == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{typed}
|
||||
case []string:
|
||||
return append([]string{}, typed...)
|
||||
case []any:
|
||||
result := make([]string, 0, len(typed))
|
||||
for _, item := range typed {
|
||||
if text := singBoxString(item); text != "" {
|
||||
result = append(result, text)
|
||||
}
|
||||
}
|
||||
return result
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
@@ -251,7 +352,7 @@ func singBoxString(value any) string {
|
||||
case nil:
|
||||
return ""
|
||||
default:
|
||||
return ""
|
||||
return toString(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ type NodeServerConfig struct {
|
||||
TlsSettings any `json:"tls_settings,omitempty"`
|
||||
Flow any `json:"flow,omitempty"`
|
||||
Multiplex any `json:"multiplex,omitempty"`
|
||||
UTLS any `json:"utls,omitempty"`
|
||||
UpMbps any `json:"up_mbps,omitempty"`
|
||||
DownMbps any `json:"down_mbps,omitempty"`
|
||||
Version any `json:"version,omitempty"`
|
||||
@@ -265,10 +266,12 @@ func BuildNodeConfig(node *model.Server) NodeServerConfig {
|
||||
case "vmess":
|
||||
response.Tls = getMapInt(settings, "tls")
|
||||
response.Multiplex = getMapAny(settings, "multiplex")
|
||||
response.UTLS = getMapAny(settings, "utls")
|
||||
case "trojan":
|
||||
response.Host = node.Host
|
||||
response.ServerName = getMapString(settings, "server_name")
|
||||
response.Multiplex = getMapAny(settings, "multiplex")
|
||||
response.UTLS = getMapAny(settings, "utls")
|
||||
response.Tls = getMapInt(settings, "tls")
|
||||
if getMapInt(settings, "tls") == 2 {
|
||||
response.TlsSettings = getMapAny(settings, "reality_settings")
|
||||
@@ -279,6 +282,7 @@ func BuildNodeConfig(node *model.Server) NodeServerConfig {
|
||||
response.Tls = getMapInt(settings, "tls")
|
||||
response.Flow = getMapString(settings, "flow")
|
||||
response.Multiplex = getMapAny(settings, "multiplex")
|
||||
response.UTLS = getMapAny(settings, "utls")
|
||||
response.Decryption = nil
|
||||
if encryption, ok := settings["encryption"].(map[string]any); ok {
|
||||
if enabled, ok := encryption["enabled"].(bool); ok && enabled {
|
||||
|
||||
Reference in New Issue
Block a user