Files
3x-ui/internal/web/service/reality_scan_test.go
T
MHSanaei 6964d84742 feat(reality): add live REALITY target scanner with IP/CIDR discovery
Replace the static reality-targets list with a server-side TLS 1.3 probe that checks TLS 1.3 + HTTP/2 + X25519 + a trusted certificate.

- Single-domain validate auto-fills target and serverNames from the cert SAN
- Discovery scans an IP/CIDR without SNI to find new targets from their certificates, deduped and ranked by feasibility then latency, private-IP guarded via netsafe
- New endpoints scanRealityTarget and scanRealityTargets with RealityScanResult, plus openapigen and api-docs entries
- Add scanner strings to all 13 locales
- Replace deprecated AntD Alert message prop with title across the panel
2026-06-26 22:18:47 +02:00

112 lines
3.0 KiB
Go

package service
import (
"crypto/tls"
"testing"
)
func TestTLSVersionName(t *testing.T) {
cases := map[uint16]string{
tls.VersionTLS13: "1.3",
tls.VersionTLS12: "1.2",
tls.VersionTLS11: "1.1",
tls.VersionTLS10: "1.0",
0: "unknown",
}
for in, want := range cases {
if got := tlsVersionName(in); got != want {
t.Errorf("tlsVersionName(%d) = %q, want %q", in, got, want)
}
}
}
func TestRealityCurveName(t *testing.T) {
cases := map[tls.CurveID]string{
tls.X25519: "X25519",
tls.X25519MLKEM768: "X25519MLKEM768",
tls.CurveP256: "P-256",
0: "",
}
for in, want := range cases {
if got := realityCurveName(in); got != want {
t.Errorf("realityCurveName(%d) = %q, want %q", in, got, want)
}
}
}
func TestFilterUsableSANs(t *testing.T) {
got := filterUsableSANs([]string{"example.com", "*.example.com", "", " a.com "})
want := []string{"example.com", "a.com"}
if len(got) != len(want) {
t.Fatalf("filterUsableSANs = %v, want %v", got, want)
}
for i := range want {
if got[i] != want[i] {
t.Errorf("filterUsableSANs[%d] = %q, want %q", i, got[i], want[i])
}
}
}
func TestSplitRealityTarget(t *testing.T) {
okCases := []struct {
in string
wantHost string
wantPort int
}{
{"example.com", "example.com", 443},
{"example.com:8443", "example.com", 8443},
{"1.1.1.1:443", "1.1.1.1", 443},
}
for _, c := range okCases {
host, port, err := splitRealityTarget(c.in)
if err != nil {
t.Errorf("splitRealityTarget(%q) unexpected error: %v", c.in, err)
continue
}
if host != c.wantHost || port != c.wantPort {
t.Errorf("splitRealityTarget(%q) = (%q, %d), want (%q, %d)", c.in, host, port, c.wantHost, c.wantPort)
}
}
badCases := []string{"", " ", "example.com:0", "example.com:70000", "bad host!"}
for _, in := range badCases {
if _, _, err := splitRealityTarget(in); err == nil {
t.Errorf("splitRealityTarget(%q) expected error, got nil", in)
}
}
}
func TestScanRealityTargetInputValidation(t *testing.T) {
if _, err := (&ServerService{}).ScanRealityTarget(""); err == nil {
t.Error("ScanRealityTarget(empty) expected error, got nil")
}
}
func TestScanRealityTargetBlocksPrivate(t *testing.T) {
res, err := (&ServerService{}).ScanRealityTarget("127.0.0.1:443")
if err != nil {
t.Fatalf("ScanRealityTarget(loopback) unexpected error: %v", err)
}
if res.Feasible {
t.Error("ScanRealityTarget(loopback) should not be feasible")
}
if res.Reason == "" {
t.Error("ScanRealityTarget(loopback) should set a reason")
}
}
func TestScanRealityTargetsHandlesPrivateAndBadInput(t *testing.T) {
results, err := (&ServerService{}).ScanRealityTargets("127.0.0.1:443,10.0.0.1:443,bad host!")
if err != nil {
t.Fatalf("ScanRealityTargets unexpected error: %v", err)
}
if len(results) != 3 {
t.Fatalf("ScanRealityTargets returned %d results, want 3", len(results))
}
for _, r := range results {
if r.Feasible {
t.Errorf("result %q unexpectedly feasible", r.Target)
}
}
}