mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-22 09:46:37 +08:00
fix(link): sanitize numeric quicParams taken from a share link's fm= param
The fm= finalmask blob was JSON-decoded and attached to streamSettings verbatim, both by the Go parser (outbound subscriptions) and the frontend import. Some providers emit duration strings for the strictly integer quicParams fields (e.g. keepAlivePeriod "10s"), and xray-core then refuses to load the whole config at startup - one bad subscription entry took the panel's Xray down on the next refresh. Coerce numeric strings, convert duration strings to whole seconds, and drop values that cannot be represented as integers; genuinely string-typed fields (congestion, bbrProfile, brutalUp/Down, udpHop) pass through untouched. Closes #5783
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -35,6 +36,44 @@ func TestParseVlessLink(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseVlessLink_FinalMaskQuicParamsSanitized(t *testing.T) {
|
||||
fm := url.QueryEscape(`{"mask":"dtls","quicParams":{"keepAlivePeriod":"10s","maxIdleTimeout":"30","initStreamReceiveWindow":524288,"maxIncomingStreams":true,"brutalUp":"100 mbps"}}`)
|
||||
res, err := ParseLink("vless://uuid@1.2.3.4:443?type=tcp&security=none&fm=" + fm + "#node1")
|
||||
if err != nil {
|
||||
t.Fatalf("parse vless with fm: %v", err)
|
||||
}
|
||||
stream, ok := res.Outbound["streamSettings"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("missing streamSettings: %v", res.Outbound)
|
||||
}
|
||||
finalmask, ok := stream["finalmask"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("missing finalmask: %v", stream)
|
||||
}
|
||||
if finalmask["mask"] != "dtls" {
|
||||
t.Errorf("mask changed: %v", finalmask["mask"])
|
||||
}
|
||||
qp, ok := finalmask["quicParams"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("missing quicParams: %v", finalmask)
|
||||
}
|
||||
if got := qp["keepAlivePeriod"]; got != float64(10) {
|
||||
t.Errorf("keepAlivePeriod: expected 10, got %v (%T)", got, got)
|
||||
}
|
||||
if got := qp["maxIdleTimeout"]; got != float64(30) {
|
||||
t.Errorf("maxIdleTimeout: expected 30, got %v (%T)", got, got)
|
||||
}
|
||||
if got := qp["initStreamReceiveWindow"]; got != float64(524288) {
|
||||
t.Errorf("initStreamReceiveWindow: expected 524288, got %v (%T)", got, got)
|
||||
}
|
||||
if _, exists := qp["maxIncomingStreams"]; exists {
|
||||
t.Errorf("maxIncomingStreams should be dropped, got %v", qp["maxIncomingStreams"])
|
||||
}
|
||||
if got := qp["brutalUp"]; got != "100 mbps" {
|
||||
t.Errorf("brutalUp should stay a string, got %v (%T)", got, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSubscriptionBody_Base64(t *testing.T) {
|
||||
// base64 of the two joined links:
|
||||
// vless://u@h:443?type=tcp#A\nvless://u2@h2:443?type=tcp#B
|
||||
|
||||
Reference in New Issue
Block a user