mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-13 16:16:06 +00:00
1f2e3e1447
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
108 lines
3.3 KiB
Go
108 lines
3.3 KiB
Go
package sub
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
// shareLinkInbound builds a VLESS inbound with one client and the given stream
|
|
// settings, mirroring flowTestInbound but without forcing a flow.
|
|
func shareLinkInbound(streamSettings string) *model.Inbound {
|
|
return &model.Inbound{
|
|
Listen: "203.0.113.1",
|
|
Port: 443,
|
|
Protocol: model.VLESS,
|
|
Remark: "sharelink",
|
|
Settings: `{"clients":[{"id":"11111111-2222-4333-8444-555555555555","email":"user"}],"decryption":"none","encryption":"none"}`,
|
|
StreamSettings: streamSettings,
|
|
}
|
|
}
|
|
|
|
// TestGenVlessLink_TLSParamsMapped locks every field that applyShareTLSParams
|
|
// (service.go:1029) writes into a TLS share link. Without these assertions a mutant
|
|
// that drops `sni`, swaps a key, or skips `pcs`/`alpn`/`fp` survives the whole suite —
|
|
// the existing flow tests only check `flow=`.
|
|
func TestGenVlessLink_TLSParamsMapped(t *testing.T) {
|
|
stream := `{
|
|
"network":"tcp","security":"tls",
|
|
"tcpSettings":{"header":{"type":"none"}},
|
|
"tlsSettings":{
|
|
"serverName":"sni.example.com",
|
|
"alpn":["h2","http/1.1"],
|
|
"settings":{"fingerprint":"chrome","pinnedPeerCertSha256":["YWJj"]}
|
|
}
|
|
}`
|
|
s := &SubService{}
|
|
link := s.genVlessLink(shareLinkInbound(stream), "user")
|
|
|
|
// url.Values.Encode() percent-encodes values: "," -> %2C, "/" -> %2F.
|
|
wants := []string{
|
|
"security=tls",
|
|
"sni=sni.example.com",
|
|
"fp=chrome",
|
|
"alpn=h2%2Chttp%2F1.1",
|
|
"pcs=YWJj",
|
|
}
|
|
for _, w := range wants {
|
|
if !strings.Contains(link, w) {
|
|
t.Fatalf("TLS link missing %q\n got: %s", w, link)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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"}},
|
|
"realitySettings":{
|
|
"serverNames":["reality.example.com"],
|
|
"shortIds":["ab12cd"],
|
|
"settings":{"publicKey":"PBKvalue","fingerprint":"firefox"}
|
|
}
|
|
}`
|
|
s := &SubService{}
|
|
link := s.genVlessLink(shareLinkInbound(stream), "user")
|
|
|
|
if !strings.Contains(link, "spx=%2F") {
|
|
t.Fatalf("reality link missing random spx fallback\n got: %s", link)
|
|
}
|
|
}
|