Browse Source

fix(link): honor the vmess ws path and hysteria2 vcn params on import

Two Go/TS parser parity gaps in the outbound share-link import path: parseVmess
only applied a ws link's path when the inner JSON also carried a host key, so a
generator that omits host dropped the path back to the default; and parseHysteria2
hardcoded verifyPeerCertByName to empty, ignoring the vcn param the panel emits,
so a hysteria2 outbound with a decoy SNI and a distinct cert name failed TLS
verification after import. The TS parser handles both; make the Go parser match.
MHSanaei 1 ngày trước cách đây
mục cha
commit
83de6e75e0

+ 3 - 4
internal/util/link/outbound.go

@@ -157,9 +157,8 @@ func parseVmess(link string) (*ParseResult, error) {
 	// Map known fields (best effort, matching frontend parser coverage)
 	switch network {
 	case "ws":
-		if host, ok := j["host"].(string); ok {
-			setWS(stream, host, getString(j, "path", "/"))
-		}
+		host, _ := j["host"].(string)
+		setWS(stream, host, getString(j, "path", "/"))
 	case "grpc":
 		svc := getString(j, "path", "")
 		if auth, ok := j["authority"].(string); ok && auth != "" {
@@ -452,7 +451,7 @@ func parseHysteria2(link string) (*ParseResult, error) {
 			"alpn":                 splitCommaOrDefault(params.Get("alpn"), []string{"h3"}),
 			"fingerprint":          params.Get("fp"),
 			"echConfigList":        params.Get("ech"),
-			"verifyPeerCertByName": "",
+			"verifyPeerCertByName": params.Get("vcn"),
 			"pinnedPeerCertSha256": params.Get("pinSHA256"),
 		},
 	}

+ 26 - 0
internal/util/link/outbound_helpers_test.go

@@ -177,6 +177,32 @@ func TestParse_XhttpExtraAndSnakeCaseFields(t *testing.T) {
 	}
 }
 
+func TestParse_VmessWSPathWithoutHostKey(t *testing.T) {
+	// Some generators omit "host" when it equals the address; the path must
+	// still be honored (matching the TS parser), not dropped to the default.
+	inner := `{"v":"2","add":"h","port":443,"id":"11111111-2222-4333-8444-555555555555","net":"ws","path":"/api","tls":"tls"}`
+	link := "vmess://" + base64.StdEncoding.EncodeToString([]byte(inner))
+	res, err := ParseLink(link)
+	if err != nil {
+		t.Fatalf("parse: %v", err)
+	}
+	wss := streamSub(t, res, "wsSettings")
+	if wss["path"] != "/api" {
+		t.Errorf("wsSettings path = %v, want /api (dropped when host key absent)", wss["path"])
+	}
+}
+
+func TestParse_Hysteria2VerifyPeerCertByName(t *testing.T) {
+	res, err := ParseLink("hysteria2://[email protected]:443?security=tls&sni=decoy.com&vcn=real-cert.com#r")
+	if err != nil {
+		t.Fatalf("parse: %v", err)
+	}
+	tls := streamSub(t, res, "tlsSettings")
+	if tls["verifyPeerCertByName"] != "real-cert.com" {
+		t.Errorf("verifyPeerCertByName = %v, want real-cert.com (vcn param ignored)", tls["verifyPeerCertByName"])
+	}
+}
+
 func TestParse_TCPHTTPHeader(t *testing.T) {
 	res, err := ParseLink("vless://[email protected]:443?type=tcp&headerType=http&host=ex.com&path=%2F")
 	if err != nil {