Per SETTINGS-AUDIT (all three tiers approved 2026-10-23): Dead settings: - panelOutbound, ipLimitAllowlist (+ orphan parser job), outboundDownThreshold - tg fake events outbound.down/outbound.up/xray.crash (no publisher in lite) - phantom routing sub-tabs (Happ/Clash/Incy) and subJsonRules direct-rules tab (no backend keys); subHideSettings moved to the subscription info tab first Upstream remnants: - ldap* / smtp* model+schema keys, EmailNotifications orphan component - twoFactorEnable/twoFactorToken + login-page probe (no backend handler) - externalTrafficInform* Newly approved removals: - JSON subscription family (producer, routes, UA auto-detect, mux/finalmask/ observatory) and Clash subscription family (producer, routes, UA detect) - SubBalancer (table, service, controller, settings tab) - subThemeDir (subscription page falls back to the built-in template) - datepicker jalalian option (gregorian only; Persian picker removed) JSON/Clash endpoints now 404; link-format output pinned by regression tests. Guarded keys untouched: webListen/webPort/webBasePath/certs, tg* chain, expireDiff/trafficDiff/tgBotProxy, subHideSettings, pageSize/tgLang.
106 lines
3.7 KiB
Go
106 lines
3.7 KiB
Go
package sub
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
func TestGetSubsToleratesUnusualStreamSettings(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
cases := []struct {
|
|
name string
|
|
stream string
|
|
}{
|
|
{"reality empty arrays", `{"network":"tcp","security":"reality","realitySettings":{"serverNames":[],"shortIds":[],"settings":{"publicKey":"pk"}}}`},
|
|
{"tcp http missing request", `{"network":"tcp","security":"none","tcpSettings":{"header":{"type":"http","response":{"headers":{}}}}}`},
|
|
{"tcp http empty path", `{"network":"tcp","security":"none","tcpSettings":{"header":{"type":"http","request":{"path":[]}}}}`},
|
|
{"grpc missing keys", `{"network":"grpc","security":"none","grpcSettings":{}}`},
|
|
{"empty stream settings", `{}`},
|
|
{"ws missing wsSettings", `{"network":"ws","security":"none"}`},
|
|
{"httpupgrade missing settings", `{"network":"httpupgrade","security":"none"}`},
|
|
{"tls alpn non-string element", `{"network":"tcp","security":"tls","tlsSettings":{"alpn":[123]}}`},
|
|
}
|
|
|
|
for i, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
seedSubDB(t)
|
|
subId := fmt.Sprintf("s%d", i)
|
|
seedSubInbound(t, subId, fmt.Sprintf("t%d", i), 46000+i, 1, tc.stream)
|
|
|
|
links, _, _, _, err := NewSubService("").GetSubs(subId, "req.example.com")
|
|
if err != nil {
|
|
t.Fatalf("GetSubs errored: %v", err)
|
|
}
|
|
if len(links) != 1 {
|
|
t.Fatalf("expected 1 share link, got %d", len(links))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetSubsToleratesHysteriaWithoutHysteriaSettings(t *testing.T) {
|
|
seedSubDB(t)
|
|
db := database.GetDB()
|
|
|
|
const subId = "hy1"
|
|
const email = "hy@e"
|
|
ib := &model.Inbound{
|
|
UserId: 1, Tag: "hy", Enable: true, Listen: "203.0.113.5", Port: 46200,
|
|
Protocol: model.Hysteria,
|
|
Remark: "hy",
|
|
Settings: fmt.Sprintf(`{"version":2,"clients":[{"auth":"hyauth","email":%q,"subId":%q,"enable":true}]}`, email, subId),
|
|
StreamSettings: `{"security":"tls","tlsSettings":{"serverName":"hy.sni"}}`,
|
|
}
|
|
if err := db.Create(ib).Error; err != nil {
|
|
t.Fatalf("seed inbound: %v", err)
|
|
}
|
|
client := &model.ClientRecord{Email: email, SubID: subId, Enable: true}
|
|
if err := db.Create(client).Error; err != nil {
|
|
t.Fatalf("seed client: %v", err)
|
|
}
|
|
if err := db.Create(&model.ClientInbound{ClientId: client.Id, InboundId: ib.Id}).Error; err != nil {
|
|
t.Fatalf("seed client_inbound: %v", err)
|
|
}
|
|
|
|
links, _, _, _, err := NewSubService("").GetSubs(subId, "sub.example.com")
|
|
if err != nil {
|
|
t.Fatalf("GetSubs: %v", err)
|
|
}
|
|
if len(links) != 1 {
|
|
t.Fatalf("expected 1 share link for a hysteria inbound without hysteriaSettings, got %d", len(links))
|
|
}
|
|
}
|
|
|
|
func TestGetSubsToleratesNonStringRealityShortId(t *testing.T) {
|
|
seedSubDB(t)
|
|
stream := `{"network":"tcp","security":"reality","realitySettings":{"serverNames":["sni.example.com"],"shortIds":[42],"settings":{"publicKey":"pk"}}}`
|
|
seedSubInbound(t, "rlty1", "rlty", 46400, 1, stream)
|
|
|
|
links, _, _, _, err := NewSubService("").GetSubs("rlty1", "sub.example.com")
|
|
if err != nil {
|
|
t.Fatalf("GetSubs: %v", err)
|
|
}
|
|
if len(links) != 1 {
|
|
t.Fatalf("expected 1 share link for a reality inbound with a non-string shortId element, got %d", len(links))
|
|
}
|
|
}
|
|
|
|
func TestGetSubsToleratesExternalProxyMissingPort(t *testing.T) {
|
|
seedSubDB(t)
|
|
stream := `{"network":"tcp","security":"none","externalProxy":[{"forceTls":"same","dest":"cdn.example.com"}]}`
|
|
seedSubInbound(t, "extp1", "extp", 46500, 1, stream)
|
|
|
|
links, _, _, _, err := NewSubService("").GetSubs("extp1", "sub.example.com")
|
|
if err != nil {
|
|
t.Fatalf("GetSubs: %v", err)
|
|
}
|
|
if len(links) == 0 {
|
|
t.Fatal("GetSubs returned no links for an externalProxy entry missing port")
|
|
}
|
|
}
|