Browse Source

fix(sub): omit non-standard fm param from Hysteria2 URI (#6048)

Hysteria2 subscription links included a v2rayN-specific fm=<json>
finalmask dump alongside standard obfs/obfs-password. Clients such as
mihomo reject the unknown query param and fail to update the provider.

Emit only the standard salamander fields in genHysteriaLink, matching
the Clash generator.

Fixes #5982
H-TTTTT 18 hours ago
parent
commit
fde66ba820
2 changed files with 32 additions and 4 deletions
  1. 3 4
      internal/sub/service.go
  2. 29 0
      internal/sub/service_test.go

+ 3 - 4
internal/sub/service.go

@@ -1025,11 +1025,10 @@ func (s *SubService) genHysteriaLink(inbound *model.Inbound, email string) strin
 		}
 	}
 
-	// salamander obfs (Hysteria2). The panel-side link generator already
-	// emits these; keep the subscription output in sync so a client has
-	// the obfs password to match the server.
+	// salamander obfs (Hysteria2). Emit only the standard URI fields;
+	// the non-standard fm=<json> finalmask dump breaks mihomo and other
+	// Hysteria2 clients that reject unknown query params.
 	if finalmask, ok := stream["finalmask"].(map[string]any); ok {
-		applyFinalMaskParams(finalmask, params)
 		if udpMasks, ok := finalmask["udp"].([]any); ok {
 			for _, m := range udpMasks {
 				mask, _ := m.(map[string]any)

+ 29 - 0
internal/sub/service_test.go

@@ -1110,3 +1110,32 @@ func TestHysteriaHopPorts(t *testing.T) {
 		})
 	}
 }
+
+func TestGenHysteriaLinkOmitsFinalMaskQueryParam(t *testing.T) {
+	stream := `{
+		"security":"tls",
+		"tlsSettings":{"serverName":"hy.sni","alpn":["h3"],"settings":{"fingerprint":"chrome"}},
+		"finalmask":{"udp":[{"type":"salamander","settings":{"password":"obfs-secret"}}]}
+	}`
+	in := &model.Inbound{
+		Listen:         "203.0.113.1",
+		Port:           443,
+		Protocol:       model.Hysteria,
+		Remark:         "hy2",
+		Settings:       `{"version":2,"clients":[{"auth":"hyauth","email":"user"}]}`,
+		StreamSettings: stream,
+	}
+	got := (&SubService{}).genHysteriaLink(in, "user")
+	if got == "" {
+		t.Fatal("expected hysteria2 link")
+	}
+	if strings.Contains(got, "fm=") {
+		t.Fatalf("hysteria2 subscription URI must not include non-standard fm param: %s", got)
+	}
+	if !strings.Contains(got, "obfs=salamander") {
+		t.Fatalf("missing standard obfs=salamander: %s", got)
+	}
+	if !strings.Contains(got, "obfs-password=obfs-secret") {
+		t.Fatalf("missing standard obfs-password: %s", got)
+	}
+}