Files
Ant-Browser/backend/test/proxy/trojan_test.go
T
Ant Browser Release Bot 6f58a6c19a publish: 1.0.0 snapshot (bad2ec1)
channel: master
version: 1.0.0
source-ref: master
published-at-utc: 2026-03-13T15:19:28Z
2026-03-13 23:19:29 +08:00

229 lines
6.6 KiB
Go

package proxy_test
import (
"encoding/base64"
"encoding/json"
"fmt"
"testing"
"ant-chrome/backend/internal/proxy"
)
func TestTrojanClashYAML(t *testing.T) {
node := `- name: JP02|日本|x1.0
type: trojan
server: trojan.example.com
port: 443
password: example-password
udp: true
skip-cert-verify: true
network: tcp`
standard, outbound, err := proxy.ParseProxyNode(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
if standard != "" {
t.Fatalf("期望 outbound,得到 standard: %s", standard)
}
data, _ := json.MarshalIndent(outbound, "", " ")
t.Logf("trojan clash outbound:\n%s", string(data))
if outbound["protocol"] != "trojan" {
t.Errorf("protocol 期望 trojan,得到 %v", outbound["protocol"])
}
settings := outbound["settings"].(map[string]interface{})
if settings["address"] != "trojan.example.com" {
t.Errorf("address 不匹配: %v", settings["address"])
}
if settings["password"] != "example-password" {
t.Errorf("password 不匹配: %v", settings["password"])
}
stream := outbound["streamSettings"].(map[string]interface{})
if stream["security"] != "tls" {
t.Errorf("security 期望 tls,得到 %v", stream["security"])
}
tls := stream["tlsSettings"].(map[string]interface{})
if tls["allowInsecure"] != true {
t.Errorf("allowInsecure 期望 true,得到 %v", tls["allowInsecure"])
}
}
func TestTrojanURI(t *testing.T) {
node := "trojan://mypassword@example.com:443?sni=example.com&allowInsecure=1"
_, outbound, err := proxy.ParseProxyNode(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
if outbound["protocol"] != "trojan" {
t.Errorf("protocol 期望 trojan,得到 %v", outbound["protocol"])
}
settings := outbound["settings"].(map[string]interface{})
if settings["address"] != "example.com" {
t.Errorf("address 不匹配: %v", settings["address"])
}
if settings["password"] != "mypassword" {
t.Errorf("password 不匹配: %v", settings["password"])
}
}
func TestSSClashYAML(t *testing.T) {
node := `- name: SS节点
type: ss
server: 1.2.3.4
port: 8388
cipher: aes-256-gcm
password: testpassword`
_, outbound, err := proxy.ParseProxyNode(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
data, _ := json.MarshalIndent(outbound, "", " ")
t.Logf("SS clash outbound:\n%s", string(data))
if outbound["protocol"] != "shadowsocks" {
t.Errorf("protocol 期望 shadowsocks,得到 %v", outbound["protocol"])
}
settings := outbound["settings"].(map[string]interface{})
if settings["address"] != "1.2.3.4" {
t.Errorf("address 不匹配: %v", settings["address"])
}
if settings["method"] != "aes-256-gcm" {
t.Errorf("method 不匹配: %v", settings["method"])
}
if settings["password"] != "testpassword" {
t.Errorf("password 不匹配: %v", settings["password"])
}
}
func TestSSURI_SIP002(t *testing.T) {
// SIP002: ss://BASE64(method:password)@host:port#name
userInfo := base64.StdEncoding.EncodeToString([]byte("aes-256-gcm:mypassword"))
node := fmt.Sprintf("ss://%s@1.2.3.4:8388#测试节点", userInfo)
_, outbound, err := proxy.ParseProxyNode(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
data, _ := json.MarshalIndent(outbound, "", " ")
t.Logf("SS SIP002 outbound:\n%s", string(data))
settings := outbound["settings"].(map[string]interface{})
if settings["method"] != "aes-256-gcm" {
t.Errorf("method 不匹配: %v", settings["method"])
}
if settings["password"] != "mypassword" {
t.Errorf("password 不匹配: %v", settings["password"])
}
if settings["address"] != "1.2.3.4" {
t.Errorf("address 不匹配: %v", settings["address"])
}
}
func TestSSURI_Legacy(t *testing.T) {
// 旧格式: ss://BASE64(method:password@host:port)
raw := base64.StdEncoding.EncodeToString([]byte("chacha20-ietf-poly1305:pass123@2.3.4.5:443"))
node := "ss://" + raw
_, outbound, err := proxy.ParseProxyNode(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
settings := outbound["settings"].(map[string]interface{})
if settings["method"] != "chacha20-ietf-poly1305" {
t.Errorf("method 不匹配: %v", settings["method"])
}
if settings["address"] != "2.3.4.5" {
t.Errorf("address 不匹配: %v", settings["address"])
}
t.Logf("SS legacy outbound OK: %v", settings)
}
func TestSSR_Unsupported(t *testing.T) {
node := "ssr://somebase64data"
_, _, err := proxy.ParseProxyNode(node)
if err == nil {
t.Fatal("期望 SSR 返回错误,但没有")
}
t.Logf("SSR 正确返回错误: %v", err)
}
func TestHysteria2URI(t *testing.T) {
node := "hysteria2://mypassword@example.com:443?sni=example.com&insecure=1"
outbound, err := proxy.BuildSingBoxOutbound(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
data, _ := json.MarshalIndent(outbound, "", " ")
t.Logf("hysteria2 URI outbound:\n%s", string(data))
if outbound["type"] != "hysteria2" {
t.Errorf("type 期望 hysteria2,得到 %v", outbound["type"])
}
if outbound["server"] != "example.com" {
t.Errorf("server 不匹配: %v", outbound["server"])
}
if outbound["password"] != "mypassword" {
t.Errorf("password 不匹配: %v", outbound["password"])
}
tls := outbound["tls"].(map[string]interface{})
if tls["insecure"] != true {
t.Errorf("insecure 期望 true,得到 %v", tls["insecure"])
}
}
func TestHysteria2ClashYAML(t *testing.T) {
node := `- name: HY2节点
type: hysteria2
server: example.com
port: 443
password: testpass
sni: example.com
skip-cert-verify: false`
outbound, err := proxy.BuildSingBoxOutbound(node)
if err != nil {
t.Fatalf("解析失败: %v", err)
}
data, _ := json.MarshalIndent(outbound, "", " ")
t.Logf("hysteria2 clash outbound:\n%s", string(data))
if outbound["type"] != "hysteria2" {
t.Errorf("type 期望 hysteria2,得到 %v", outbound["type"])
}
if outbound["server"] != "example.com" {
t.Errorf("server 不匹配: %v", outbound["server"])
}
tls := outbound["tls"].(map[string]interface{})
if tls["server_name"] != "example.com" {
t.Errorf("server_name 不匹配: %v", tls["server_name"])
}
}
func TestIsSingBoxProtocol(t *testing.T) {
cases := []struct {
input string
expected bool
}{
{"hysteria2://pass@host:443", true},
{"hysteria://pass@host:443", true},
{"- name: n\n type: hysteria2\n server: h\n port: 443", true},
{"- name: n\n type: tuic\n server: h\n port: 443", true},
{"vmess://xxx", false},
{"trojan://pass@host:443", false},
{"socks5://127.0.0.1:1080", false},
}
for _, c := range cases {
got := proxy.IsSingBoxProtocol(c.input)
if got != c.expected {
t.Errorf("IsSingBoxProtocol(%q) = %v, 期望 %v", c.input[:min(30, len(c.input))], got, c.expected)
}
}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}