mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 19:25:05 +03:00
fix(link): accept padded URL-safe base64 in vmess links (#6975)
parseVmess tried standard base64, then unpadded URL-safe base64, so a URL-safe body that kept its = padding failed both and the server silently dropped out of an imported outbound subscription. It now uses base64DecodeFlexible, the helper the shadowsocks parser already uses.
This commit is contained in:
@@ -208,17 +208,13 @@ func dropHostLocalKeys(v any) {
|
||||
|
||||
func parseVmess(link string) (*ParseResult, error) {
|
||||
b64 := strings.TrimPrefix(link, "vmess://")
|
||||
// vmess:// base64(json)
|
||||
raw, err := base64.StdEncoding.DecodeString(padBase64(b64))
|
||||
if err != nil {
|
||||
// Some providers use raw URL-safe
|
||||
raw, err = base64.RawURLEncoding.DecodeString(b64)
|
||||
}
|
||||
// vmess:// base64(json), standard or URL-safe, padded or not
|
||||
raw, err := base64DecodeFlexible(b64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("vmess decode: %w", err)
|
||||
}
|
||||
var j map[string]any
|
||||
if err := json.Unmarshal(raw, &j); err != nil {
|
||||
if err := json.Unmarshal([]byte(raw), &j); err != nil {
|
||||
return nil, fmt.Errorf("vmess json: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,33 @@ func TestParseVmessLink(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseVmessLinkBase64Alphabets(t *testing.T) {
|
||||
raw := []byte(`{"v":"2","ps":"a?>","add":"1.2.3.4","port":443,"id":"uuid","net":"ws","path":"/?","tls":"tls"}`)
|
||||
if padded := base64.URLEncoding.EncodeToString(raw); !strings.ContainsAny(padded, "-_") || !strings.HasSuffix(padded, "=") {
|
||||
t.Fatalf("test object must encode to URL-safe characters with padding, got %s", padded)
|
||||
}
|
||||
cases := []struct {
|
||||
name string
|
||||
b64 string
|
||||
}{
|
||||
{"standard", base64.StdEncoding.EncodeToString(raw)},
|
||||
{"standard unpadded", base64.RawStdEncoding.EncodeToString(raw)},
|
||||
{"url-safe", base64.URLEncoding.EncodeToString(raw)},
|
||||
{"url-safe unpadded", base64.RawURLEncoding.EncodeToString(raw)},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
res, err := ParseLink("vmess://" + c.b64)
|
||||
if err != nil {
|
||||
t.Fatalf("parse %s: %v", c.b64, err)
|
||||
}
|
||||
if res.Outbound["tag"] != "a?>" {
|
||||
t.Errorf("tag = %v, want %q", res.Outbound["tag"], "a?>")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkIdentityKeepsTLSServerName(t *testing.T) {
|
||||
a, errA := ParseLink("vless://uuid@1.2.3.4:443?type=ws&security=tls&sni=a.example.com#node")
|
||||
b, errB := ParseLink("vless://uuid@1.2.3.4:443?type=ws&security=tls&sni=b.example.com#node")
|
||||
|
||||
Reference in New Issue
Block a user