mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-09 14:16:07 +00:00
fix(sub): use configured spiderX instead of always randomizing
applyShareRealityParams and SubJsonService.realityData generated a fresh random spx on every export, so share links, "export all links", and JSON subscriptions never matched a spiderX configured on the inbound and two exports of the same client disagreed with each other. Read the value from realitySettings.settings like pbk/fp/pqv and keep the random value only as a fallback when none is configured. Closes #5718
This commit is contained in:
@@ -331,8 +331,10 @@ func (s *SubJsonService) realityData(rData map[string]any) map[string]any {
|
||||
rltyData["fingerprint"] = rltyClientSettings["fingerprint"]
|
||||
rltyData["mldsa65Verify"] = rltyClientSettings["mldsa65Verify"]
|
||||
|
||||
// Set random data
|
||||
rltyData["spiderX"] = "/" + random.Seq(15)
|
||||
if spx, ok := rltyClientSettings["spiderX"].(string); ok && spx != "" {
|
||||
rltyData["spiderX"] = spx
|
||||
}
|
||||
shortIds, ok := rData["shortIds"].([]any)
|
||||
if ok && len(shortIds) > 0 {
|
||||
rltyData["shortId"] = shortIds[random.Num(len(shortIds))].(string)
|
||||
|
||||
@@ -254,3 +254,46 @@ func TestSubJsonServiceGlobalMuxWhenNoXmux(t *testing.T) {
|
||||
t.Fatalf("mux payload wrong: %#v", m)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubJsonServiceRealityDataUsesConfiguredSpiderX(t *testing.T) {
|
||||
svc := NewSubJsonService("", "", "", nil)
|
||||
|
||||
stream := svc.streamData(`{
|
||||
"network":"tcp","security":"reality","tcpSettings":{"header":{"type":"none"}},
|
||||
"realitySettings":{
|
||||
"serverNames":["reality.example.com"],
|
||||
"shortIds":["ab12cd"],
|
||||
"settings":{"publicKey":"PBKvalue","fingerprint":"firefox","spiderX":"/mypath"}
|
||||
}
|
||||
}`)
|
||||
|
||||
rlty, _ := stream["realitySettings"].(map[string]any)
|
||||
if rlty == nil {
|
||||
t.Fatal("streamData dropped realitySettings")
|
||||
}
|
||||
if rlty["spiderX"] != "/mypath" {
|
||||
t.Fatalf("spiderX = %v, want configured /mypath (#5718)", rlty["spiderX"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubJsonServiceRealityDataSpiderXFallsBackToRandom(t *testing.T) {
|
||||
svc := NewSubJsonService("", "", "", nil)
|
||||
|
||||
stream := svc.streamData(`{
|
||||
"network":"tcp","security":"reality","tcpSettings":{"header":{"type":"none"}},
|
||||
"realitySettings":{
|
||||
"serverNames":["reality.example.com"],
|
||||
"shortIds":["ab12cd"],
|
||||
"settings":{"publicKey":"PBKvalue","fingerprint":"firefox"}
|
||||
}
|
||||
}`)
|
||||
|
||||
rlty, _ := stream["realitySettings"].(map[string]any)
|
||||
if rlty == nil {
|
||||
t.Fatal("streamData dropped realitySettings")
|
||||
}
|
||||
spx, _ := rlty["spiderX"].(string)
|
||||
if len(spx) != 16 || spx[0] != '/' {
|
||||
t.Fatalf("spiderX fallback = %q, want random 16-char /-prefixed value", spx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1357,6 +1357,11 @@ func applyShareRealityParams(stream map[string]any, params map[string]string) {
|
||||
}
|
||||
}
|
||||
params["spx"] = "/" + random.Seq(15)
|
||||
if spxValue, ok := searchKey(realitySettings, "spiderX"); ok {
|
||||
if spx, ok := spxValue.(string); ok && len(spx) > 0 {
|
||||
params["spx"] = spx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,43 @@ func TestGenVlessLink_TLSParamsMapped(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestGenVlessLink_RealityParamsMapped locks the reality field mapping
|
||||
// (applyShareRealityParams, service.go:1147). serverNames/shortIds are single-element
|
||||
// so random.Num is deterministic (index 0); spx is random so it is asserted by prefix.
|
||||
// Distinct pbk/sid values catch a pbk<->sid swap mutant.
|
||||
// Locks the reality field mapping of applyShareRealityParams; a configured
|
||||
// spiderX must round-trip verbatim (#5718), distinct pbk/sid catch a swap mutant.
|
||||
func TestGenVlessLink_RealityParamsMapped(t *testing.T) {
|
||||
stream := `{
|
||||
"network":"tcp","security":"reality",
|
||||
"tcpSettings":{"header":{"type":"none"}},
|
||||
"realitySettings":{
|
||||
"serverNames":["reality.example.com"],
|
||||
"shortIds":["ab12cd"],
|
||||
"settings":{"publicKey":"PBKvalue","fingerprint":"firefox","spiderX":"/mypath"}
|
||||
}
|
||||
}`
|
||||
s := &SubService{}
|
||||
link := s.genVlessLink(shareLinkInbound(stream), "user")
|
||||
|
||||
wants := []string{
|
||||
"security=reality",
|
||||
"sni=reality.example.com",
|
||||
"pbk=PBKvalue",
|
||||
"sid=ab12cd",
|
||||
"fp=firefox",
|
||||
"spx=%2Fmypath",
|
||||
}
|
||||
for _, w := range wants {
|
||||
if !strings.Contains(link, w) {
|
||||
t.Fatalf("reality link missing %q\n got: %s", w, link)
|
||||
}
|
||||
}
|
||||
// A pbk<->sid swap must not silently pass: pbk must not carry the shortId.
|
||||
if strings.Contains(link, "pbk=ab12cd") || strings.Contains(link, "sid=PBKvalue") {
|
||||
t.Fatalf("reality pbk/sid mapping crossed: %s", link)
|
||||
}
|
||||
}
|
||||
|
||||
// Without a configured spiderX, spx must still fall back to a random
|
||||
// "/"-prefixed value so clients always receive a plausible path.
|
||||
func TestGenVlessLink_RealitySpiderXFallsBackToRandom(t *testing.T) {
|
||||
stream := `{
|
||||
"network":"tcp","security":"reality",
|
||||
"tcpSettings":{"header":{"type":"none"}},
|
||||
@@ -69,21 +101,7 @@ func TestGenVlessLink_RealityParamsMapped(t *testing.T) {
|
||||
s := &SubService{}
|
||||
link := s.genVlessLink(shareLinkInbound(stream), "user")
|
||||
|
||||
wants := []string{
|
||||
"security=reality",
|
||||
"sni=reality.example.com",
|
||||
"pbk=PBKvalue",
|
||||
"sid=ab12cd",
|
||||
"fp=firefox",
|
||||
"spx=%2F", // "/" + random.Seq(15), percent-encoded leading slash
|
||||
}
|
||||
for _, w := range wants {
|
||||
if !strings.Contains(link, w) {
|
||||
t.Fatalf("reality link missing %q\n got: %s", w, link)
|
||||
}
|
||||
}
|
||||
// A pbk<->sid swap must not silently pass: pbk must not carry the shortId.
|
||||
if strings.Contains(link, "pbk=ab12cd") || strings.Contains(link, "sid=PBKvalue") {
|
||||
t.Fatalf("reality pbk/sid mapping crossed: %s", link)
|
||||
if !strings.Contains(link, "spx=%2F") {
|
||||
t.Fatalf("reality link missing random spx fallback\n got: %s", link)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user