Files
3x-ui/internal/sub/hysteria_server_description_test.go
T
冰 e897b0957a fix(sub): append host serverDescription to hysteria links (#6740)
* fix(sub): append host serverDescription to hysteria links

A host's Description reached vless/trojan/ss through buildEndpointLinks, but
genHysteriaLink renders the fragment in its own externalProxy loop and never
added the suffix, so Happ fell back to its "Hysteria | hysteria | TLS" caption
for every Hysteria server on a host that also serves VLESS (#6738).

Reuse appendHappServerDescription with the description the endpoint map already
carries, so no key lookup is duplicated and a host with no description emits the
same bytes as before. genTuicLink (service.go:912) has the same gap; left alone
to keep this diff to the reported protocol.

Regression test is red without the fix for both hysteria:// and hysteria2://.

* chore(sub): trim the hysteria serverDescription regression test

The no-description test passed with and without the #6738 fix: the empty
description branch is already pinned by TestAppendHappServerDescription, so
it certified nothing about this change. Also cut the remaining test's comment
block to the two-line limit CLAUDE.md sets.

---------

Co-authored-by: MHSanaei <ho3ein.sanaei@gmail.com>
2026-10-05 19:05:13 +02:00

58 lines
1.9 KiB
Go

package sub
import (
"encoding/json"
"strings"
"testing"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
)
// #6738: without the host's Description on hysteria(2):// links, Happ falls back
// to its own "Hysteria | hysteria | TLS" caption on a host that also serves VLESS.
func TestGenHysteriaLinkAppendsHostServerDescription(t *testing.T) {
tests := map[string]struct {
version int
scheme string
}{
"hysteria v1": {version: 1, scheme: "hysteria://"},
"hysteria v2": {version: 2, scheme: "hysteria2://"},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
host := &model.Host{
Address: "hy.example.com", Port: 443,
Remark: "Poland", ServerDescription: "Wi-Fi",
}
stream := map[string]any{
"security": "tls",
"externalProxy": []any{hostToExternalProxyMap(host, "hy.example.com", 443)},
}
rawStream, err := json.Marshal(stream)
if err != nil {
t.Fatalf("marshal stream settings: %v", err)
}
// The inbound's own `version` picks the hysteria vs hysteria2 scheme.
rawSettings, err := json.Marshal(map[string]any{
"version": tc.version,
"clients": []any{map[string]any{"auth": "secret", "email": "user"}},
})
if err != nil {
t.Fatalf("marshal inbound settings: %v", err)
}
in := &model.Inbound{
Id: 920010, Listen: "203.0.113.1", Port: 443, Protocol: model.Hysteria,
Remark: "hy", StreamSettings: string(rawStream), Settings: string(rawSettings),
}
got := (&SubService{}).genHysteriaLink(in, "user")
if !strings.HasPrefix(got, tc.scheme) {
t.Fatalf("link scheme changed.\n got: %s\nwant prefix: %s", got, tc.scheme)
}
// base64("Wi-Fi"), matching the reporter's subscription output.
if !strings.HasSuffix(got, "?serverDescription=V2ktRmk=") {
t.Fatalf("host serverDescription missing from fragment.\n got: %s\nwant suffix: ?serverDescription=V2ktRmk=", got)
}
})
}
}