service_flow_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package sub
  2. import (
  3. "strings"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. )
  7. // Issue #5232: a vision flow set on a VLESS+XHTTP+REALITY (vlessenc) client
  8. // must survive into subscription output, not just the inbound JSON.
  9. const testMlkemEncryption = "mlkem768x25519plus.native.0rtt.dGVzdC1rZXk"
  10. func TestVlessFlowAllowed(t *testing.T) {
  11. enc := map[string]any{"encryption": testMlkemEncryption}
  12. noEnc := map[string]any{"encryption": "none"}
  13. tests := []struct {
  14. name string
  15. network string
  16. security string
  17. settings map[string]any
  18. want bool
  19. }{
  20. {"tcp tls", "tcp", "tls", noEnc, true},
  21. {"tcp reality", "tcp", "reality", noEnc, true},
  22. {"tcp none", "tcp", "none", noEnc, false},
  23. {"tcp none vlessenc", "tcp", "none", enc, false},
  24. {"xhttp none vlessenc", "xhttp", "none", enc, true},
  25. {"xhttp reality vlessenc (#5232)", "xhttp", "reality", enc, true},
  26. {"xhttp tls vlessenc", "xhttp", "tls", enc, true},
  27. {"xhttp reality no vlessenc", "xhttp", "reality", noEnc, false},
  28. {"ws tls", "ws", "tls", noEnc, false},
  29. }
  30. for _, tc := range tests {
  31. t.Run(tc.name, func(t *testing.T) {
  32. if got := vlessFlowAllowed(tc.network, tc.security, tc.settings); got != tc.want {
  33. t.Fatalf("vlessFlowAllowed(%q, %q, %v) = %v, want %v", tc.network, tc.security, tc.settings, got, tc.want)
  34. }
  35. })
  36. }
  37. }
  38. func flowTestInbound(streamSettings, encryption string) *model.Inbound {
  39. return &model.Inbound{
  40. Listen: "203.0.113.1",
  41. Port: 443,
  42. Protocol: model.VLESS,
  43. Remark: "flowtest",
  44. Settings: `{"clients":[{"id":"11111111-2222-4333-8444-555555555555","email":"user","flow":"xtls-rprx-vision"}],` +
  45. `"decryption":"` + encryption + `","encryption":"` + encryption + `"}`,
  46. StreamSettings: streamSettings,
  47. }
  48. }
  49. const xhttpRealityStream = `{
  50. "network": "xhttp",
  51. "security": "reality",
  52. "xhttpSettings": {"path": "/", "mode": "auto"},
  53. "realitySettings": {
  54. "serverNames": ["example.com"],
  55. "shortIds": ["abcd"],
  56. "settings": {"publicKey": "pub", "fingerprint": "chrome"}
  57. }
  58. }`
  59. func TestGenVlessLink_FlowXhttpRealityVlessenc(t *testing.T) {
  60. s := &SubService{remarkModel: "-ieo"}
  61. link := s.genVlessLink(flowTestInbound(xhttpRealityStream, testMlkemEncryption), "user")
  62. if !strings.Contains(link, "flow=xtls-rprx-vision") {
  63. t.Fatalf("xhttp+reality+vlessenc link must carry the vision flow (#5232), got %q", link)
  64. }
  65. }
  66. func TestGenVlessLink_NoFlowXhttpRealityWithoutVlessenc(t *testing.T) {
  67. s := &SubService{remarkModel: "-ieo"}
  68. link := s.genVlessLink(flowTestInbound(xhttpRealityStream, "none"), "user")
  69. if strings.Contains(link, "flow=") {
  70. t.Fatalf("xhttp+reality without vlessenc must not carry a flow, got %q", link)
  71. }
  72. }
  73. func TestGenVlessLink_FlowTcpRealityStillWorks(t *testing.T) {
  74. stream := `{
  75. "network": "tcp",
  76. "security": "reality",
  77. "tcpSettings": {"header": {"type": "none"}},
  78. "realitySettings": {
  79. "serverNames": ["example.com"],
  80. "shortIds": ["abcd"],
  81. "settings": {"publicKey": "pub", "fingerprint": "chrome"}
  82. }
  83. }`
  84. s := &SubService{remarkModel: "-ieo"}
  85. link := s.genVlessLink(flowTestInbound(stream, "none"), "user")
  86. if !strings.Contains(link, "flow=xtls-rprx-vision") {
  87. t.Fatalf("tcp+reality link must keep the vision flow, got %q", link)
  88. }
  89. }