mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-28 00:24:19 +00:00
fix(sub): wrap JSON-subscription SS/Trojan outbound in servers[] array
The flat top-level address/method/password form only parses on recent xray-core; older bundled cores (e.g. in v2rayN) reject it. Restore the standard "servers" array used through 2.9.x so the JSON subscription connects across all xray-core versions. VMess/VLESS keep the flat vnext fallback, which is long established in xray-core.
This commit is contained in:
@@ -425,16 +425,22 @@ func (s *SubJsonService) genServer(inbound *model.Inbound, streamSettings json_u
|
||||
}
|
||||
outbound.StreamSettings = streamSettings
|
||||
|
||||
settings := map[string]any{
|
||||
// Wrap the endpoint in a "servers" array (the standard Xray schema for
|
||||
// Shadowsocks/Trojan outbounds). The flat top-level form only parses on very
|
||||
// recent xray-core; older bundled cores (e.g. in v2rayN) reject it, so SS
|
||||
// links fail to connect. See genVnext/genVless for the VMess/VLESS shape.
|
||||
server := map[string]any{
|
||||
"address": serverData[0].Address,
|
||||
"port": serverData[0].Port,
|
||||
"password": serverData[0].Password,
|
||||
"level": 8,
|
||||
}
|
||||
if inbound.Protocol == model.Shadowsocks {
|
||||
settings["method"] = serverData[0].Method
|
||||
server["method"] = serverData[0].Method
|
||||
}
|
||||
outbound.Settings = map[string]any{
|
||||
"servers": []any{server},
|
||||
}
|
||||
outbound.Settings = settings
|
||||
|
||||
result, _ := json.MarshalIndent(outbound, "", " ")
|
||||
return result
|
||||
|
||||
@@ -128,21 +128,32 @@ func TestSubJsonServiceVmessFlattened(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubJsonServiceServerFlattened(t *testing.T) {
|
||||
// Shadowsocks/Trojan outbounds must use the standard "servers" array so older
|
||||
// bundled xray-cores (e.g. v2rayN) parse them; the flat top-level form only
|
||||
// works on very recent xray-core.
|
||||
func TestSubJsonServiceServerUsesServersArray(t *testing.T) {
|
||||
trojan := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Trojan, Settings: `{}`}
|
||||
client := model.Client{Password: "p4ss"}
|
||||
|
||||
settings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(trojan, nil, client, ""))
|
||||
if _, ok := settings["servers"]; ok {
|
||||
t.Fatal("trojan outbound must not use servers array")
|
||||
server := firstServer(settings)
|
||||
if server == nil {
|
||||
t.Fatalf("trojan outbound must use a servers array, got: %#v", settings)
|
||||
}
|
||||
if settings["password"] != "p4ss" || settings["address"] != "1.2.3.4" {
|
||||
t.Fatalf("flat trojan settings wrong: %#v", settings)
|
||||
if server["password"] != "p4ss" || server["address"] != "1.2.3.4" {
|
||||
t.Fatalf("trojan server entry wrong: %#v", server)
|
||||
}
|
||||
if _, ok := server["method"]; ok {
|
||||
t.Fatalf("trojan must not carry method: %#v", server)
|
||||
}
|
||||
|
||||
ss := &model.Inbound{Listen: "1.2.3.4", Port: 443, Protocol: model.Shadowsocks, Settings: `{"method":"aes-256-gcm"}`}
|
||||
ssSettings := outboundSettings(t, NewSubJsonService("", "", "", nil).genServer(ss, nil, client, ""))
|
||||
if ssSettings["method"] != "aes-256-gcm" {
|
||||
t.Fatalf("flat shadowsocks must carry method: %#v", ssSettings)
|
||||
ssServer := firstServer(ssSettings)
|
||||
if ssServer == nil {
|
||||
t.Fatalf("shadowsocks outbound must use a servers array, got: %#v", ssSettings)
|
||||
}
|
||||
if ssServer["method"] != "aes-256-gcm" {
|
||||
t.Fatalf("shadowsocks server entry must carry method: %#v", ssServer)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user