mirror of
https://github.com/alireza0/x-ui.git
synced 2026-08-27 03:43:28 +00:00
155 lines
4.7 KiB
Go
155 lines
4.7 KiB
Go
package xray
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
// A payload built from a model.Client keeps its Go types; one read back out of
|
|
// an inbound's stored settings arrives as generic JSON values. Both reach
|
|
// AddUser, so wireguardPeerConfig has to understand both.
|
|
func wgKey(seed byte) string {
|
|
raw := make([]byte, 32)
|
|
for i := range raw {
|
|
raw[i] = seed + byte(i)
|
|
}
|
|
return base64.StdEncoding.EncodeToString(raw)
|
|
}
|
|
|
|
func TestWireguardPeerConfigTypedPayload(t *testing.T) {
|
|
peer, err := wireguardPeerConfig(map[string]interface{}{
|
|
"email": "typed@example.com",
|
|
"publicKey": wgKey(1),
|
|
"preSharedKey": wgKey(2),
|
|
"allowedIPs": []string{"10.0.0.2/32"},
|
|
"keepAlive": uint32(25),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got := peer.GetAllowedIps(); len(got) != 1 || got[0] != "10.0.0.2/32" {
|
|
t.Fatalf("allowed IPs = %v, want [10.0.0.2/32]", got)
|
|
}
|
|
if got := peer.GetKeepAlive(); got != "25" {
|
|
t.Fatalf("keepAlive = %q, want \"25\"", got)
|
|
}
|
|
if len(peer.GetPublicKey()) != 64 {
|
|
t.Fatalf("public key %q was not converted to hex", peer.GetPublicKey())
|
|
}
|
|
if len(peer.GetPreSharedKey()) != 64 {
|
|
t.Fatalf("pre-shared key %q was not converted to hex", peer.GetPreSharedKey())
|
|
}
|
|
}
|
|
|
|
func TestWireguardPeerConfigJSONPayload(t *testing.T) {
|
|
// Exactly what json.Unmarshal produces for a stored client entry.
|
|
var decoded map[string]interface{}
|
|
raw := `{"email":"json@example.com","publicKey":"` + wgKey(3) + `",
|
|
"allowedIPs":["10.0.0.3/32","fd00::3/128"],"keepAlive":30}`
|
|
if err := json.Unmarshal([]byte(raw), &decoded); err != nil {
|
|
t.Fatalf("fixture is not valid JSON: %v", err)
|
|
}
|
|
|
|
peer, err := wireguardPeerConfig(decoded)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if got := peer.GetAllowedIps(); len(got) != 2 || got[0] != "10.0.0.3/32" || got[1] != "fd00::3/128" {
|
|
t.Fatalf("allowed IPs = %v, want both entries preserved", got)
|
|
}
|
|
if got := peer.GetKeepAlive(); got != "30" {
|
|
t.Fatalf("keepAlive = %q, want \"30\" (float64 30 must not read as 0)", got)
|
|
}
|
|
}
|
|
|
|
func TestWireguardPeerConfigRejectsIncompletePeers(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
user map[string]interface{}
|
|
}{
|
|
{"no public key", map[string]interface{}{"allowedIPs": []string{"10.0.0.2/32"}}},
|
|
{"empty public key", map[string]interface{}{"publicKey": "", "allowedIPs": []string{"10.0.0.2/32"}}},
|
|
{"no allowed IPs", map[string]interface{}{"publicKey": wgKey(4)}},
|
|
{"empty allowed IPs", map[string]interface{}{"publicKey": wgKey(4), "allowedIPs": []interface{}{}}},
|
|
{"blank allowed IPs", map[string]interface{}{"publicKey": wgKey(4), "allowedIPs": []interface{}{""}}},
|
|
{"invalid public key", map[string]interface{}{"publicKey": "not a key", "allowedIPs": []string{"10.0.0.2/32"}}},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if _, err := wireguardPeerConfig(test.user); err == nil {
|
|
t.Fatal("expected an error, got none")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestWireguardPeerConfigOptionalFields(t *testing.T) {
|
|
peer, err := wireguardPeerConfig(map[string]interface{}{
|
|
"publicKey": wgKey(5),
|
|
"allowedIPs": []string{"10.0.0.5/32"},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if peer.GetPreSharedKey() != "" {
|
|
t.Fatalf("pre-shared key = %q, want empty", peer.GetPreSharedKey())
|
|
}
|
|
if peer.GetKeepAlive() != "" {
|
|
t.Fatalf("keepAlive = %q, want empty", peer.GetKeepAlive())
|
|
}
|
|
}
|
|
|
|
func TestToStringSlice(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value interface{}
|
|
want []string
|
|
}{
|
|
{"typed slice", []string{"a", "b"}, []string{"a", "b"}},
|
|
{"json slice", []interface{}{"a", "b"}, []string{"a", "b"}},
|
|
{"json slice with blanks", []interface{}{"a", "", "b"}, []string{"a", "b"}},
|
|
{"json slice with non-strings", []interface{}{"a", 7, nil}, []string{"a"}},
|
|
{"nil", nil, nil},
|
|
{"wrong type", "a,b", nil},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
got := toStringSlice(test.value)
|
|
if len(got) != len(test.want) {
|
|
t.Fatalf("got %v, want %v", got, test.want)
|
|
}
|
|
for i := range got {
|
|
if got[i] != test.want[i] {
|
|
t.Fatalf("got %v, want %v", got, test.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToUint32(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
value interface{}
|
|
want uint32
|
|
}{
|
|
{"uint32", uint32(25), 25},
|
|
{"int", 25, 25},
|
|
{"int64", int64(25), 25},
|
|
{"float64 from JSON", float64(25), 25},
|
|
{"json.Number", json.Number("25"), 25},
|
|
{"string", "25", 25},
|
|
{"zero", float64(0), 0},
|
|
{"negative", -5, 0},
|
|
{"nil", nil, 0},
|
|
{"unparsable string", "soon", 0},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got := toUint32(test.value); got != test.want {
|
|
t.Fatalf("toUint32(%v) = %d, want %d", test.value, got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|