179 lines
5.4 KiB
Go
179 lines
5.4 KiB
Go
package subscription
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
func TestParseSS_PlainUserinfo(t *testing.T) {
|
|
uri := "ss://aes-256-gcm:password123@example.com:8388#My%20Node"
|
|
got := parseSS(uri)
|
|
want := map[string]interface{}{
|
|
"name": "My Node",
|
|
"type": "ss",
|
|
"server": "example.com",
|
|
"port": 8388,
|
|
"cipher": "aes-256-gcm",
|
|
"password": "password123",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseSS() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseSS_Base64Userinfo(t *testing.T) {
|
|
userinfo := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte("aes-256-gcm:password123"))
|
|
uri := "ss://" + userinfo + "@example.com:8388#node"
|
|
got := parseSS(uri)
|
|
want := map[string]interface{}{
|
|
"name": "node",
|
|
"type": "ss",
|
|
"server": "example.com",
|
|
"port": 8388,
|
|
"cipher": "aes-256-gcm",
|
|
"password": "password123",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseSS() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseSS_WholeBodyBase64(t *testing.T) {
|
|
body := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString([]byte("aes-256-gcm:password123@example.com:8388"))
|
|
uri := "ss://" + body + "#node"
|
|
got := parseSS(uri)
|
|
want := map[string]interface{}{
|
|
"name": "node",
|
|
"type": "ss",
|
|
"server": "example.com",
|
|
"port": 8388,
|
|
"cipher": "aes-256-gcm",
|
|
"password": "password123",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseSS() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseSS_NotSS(t *testing.T) {
|
|
if got := parseSS("trojan://foo@bar:443"); got != nil {
|
|
t.Fatalf("parseSS() = %#v, want nil", got)
|
|
}
|
|
}
|
|
|
|
func TestParseTrojan_Basic(t *testing.T) {
|
|
uri := "trojan://mypassword@example.com:443?sni=sni.example.com&allowInsecure=1#My%20Trojan"
|
|
got := parseTrojan(uri)
|
|
want := map[string]interface{}{
|
|
"name": "My Trojan",
|
|
"type": "trojan",
|
|
"server": "example.com",
|
|
"port": 443,
|
|
"password": "mypassword",
|
|
"udp": true,
|
|
"sni": "sni.example.com",
|
|
"skip-cert-verify": true,
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseTrojan() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseTrojan_PeerFallback(t *testing.T) {
|
|
uri := "trojan://mypassword@example.com:443?peer=peer.example.com"
|
|
got := parseTrojan(uri)
|
|
if got["sni"] != "peer.example.com" {
|
|
t.Fatalf("expected sni from peer fallback, got %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestParseVless_TLS(t *testing.T) {
|
|
uri := "vless://uuid-1234@example.com:443?security=tls&sni=sni.example.com&fp=chrome&type=ws#node"
|
|
got := parseVless(uri)
|
|
want := map[string]interface{}{
|
|
"name": "node",
|
|
"type": "vless",
|
|
"server": "example.com",
|
|
"port": 443,
|
|
"uuid": "uuid-1234",
|
|
"udp": true,
|
|
"tls": true,
|
|
"network": "ws",
|
|
"servername": "sni.example.com",
|
|
"client-fingerprint": "chrome",
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("parseVless() = %#v, want %#v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseVless_Reality(t *testing.T) {
|
|
uri := "vless://uuid-1234@example.com:443?security=reality&pbk=publickey&sid=shortid&sni=sni.example.com"
|
|
got := parseVless(uri)
|
|
realityOpts, ok := got["reality-opts"].(map[string]interface{})
|
|
if !ok {
|
|
t.Fatalf("expected reality-opts map, got %#v", got["reality-opts"])
|
|
}
|
|
if realityOpts["public-key"] != "publickey" || realityOpts["short-id"] != "shortid" {
|
|
t.Fatalf("unexpected reality-opts: %#v", realityOpts)
|
|
}
|
|
if got["servername"] != "sni.example.com" {
|
|
t.Fatalf("expected servername set, got %#v", got["servername"])
|
|
}
|
|
if got["tls"] != true {
|
|
t.Fatalf("expected tls=true for reality, got %#v", got["tls"])
|
|
}
|
|
}
|
|
|
|
func TestParseVless_DefaultsWithoutQuery(t *testing.T) {
|
|
uri := "vless://uuid-1234@example.com:443"
|
|
got := parseVless(uri)
|
|
if got["tls"] != false || got["network"] != "tcp" || got["udp"] != true {
|
|
t.Fatalf("unexpected defaults: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestConvertContent_PassthroughExistingClashYAML(t *testing.T) {
|
|
content := "proxies:\n - name: foo\n type: ss\n"
|
|
if got := convertContent(content); got != content {
|
|
t.Fatalf("expected passthrough, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestConvertContent_PlainURIList(t *testing.T) {
|
|
content := "ss://aes-256-gcm:pw@example.com:8388#node1\ntrojan://pw2@example.com:443#node2\n"
|
|
out := convertContent(content)
|
|
var parsed map[string]interface{}
|
|
if err := yaml.Unmarshal([]byte(out), &parsed); err != nil {
|
|
t.Fatalf("output is not valid YAML: %v", err)
|
|
}
|
|
proxies, ok := parsed["proxies"].([]interface{})
|
|
if !ok || len(proxies) != 2 {
|
|
t.Fatalf("expected 2 proxies, got %#v", parsed["proxies"])
|
|
}
|
|
}
|
|
|
|
func TestConvertContent_WholeBodyBase64List(t *testing.T) {
|
|
raw := "ss://aes-256-gcm:pw@example.com:8388#node1\ntrojan://pw2@example.com:443#node2\n"
|
|
encoded := base64.StdEncoding.EncodeToString([]byte(raw))
|
|
out := convertContent(encoded)
|
|
var parsed map[string]interface{}
|
|
if err := yaml.Unmarshal([]byte(out), &parsed); err != nil {
|
|
t.Fatalf("output is not valid YAML: %v", err)
|
|
}
|
|
proxies, ok := parsed["proxies"].([]interface{})
|
|
if !ok || len(proxies) != 2 {
|
|
t.Fatalf("expected 2 proxies, got %#v", parsed["proxies"])
|
|
}
|
|
}
|
|
|
|
func TestConvertContent_UnrecognizedPassthrough(t *testing.T) {
|
|
content := "not a uri list and not yaml: [unterminated"
|
|
if got := convertContent(content); got != content {
|
|
t.Fatalf("expected passthrough of unrecognized content, got %q", got)
|
|
}
|
|
}
|