mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-25 23:35:00 +03:00
35e09191de
AmneziaWG clients accept a randomised PersistentKeepalive range such as 15-25, which makes keepalive timing harder to fingerprint; the panel only stored a single number. A client's keepalive may now be a range, validated the way AmneziaWG parses it. The downloadable .conf and vpn:// profile carry the range, Clash/Mihomo output gets its lower bound, and plain WireGuard stays scalar-only. The range lives in an additive wg_keep_alive_range column, so the integer column and an older panel binary keep working after a rollback.
98 lines
3.0 KiB
Go
98 lines
3.0 KiB
Go
package model
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestClientKeepAliveJSONPreservesRangeAndScalarCompatibility(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
want any
|
|
}{
|
|
{name: "range", input: `{"keepAlive":"15-25"}`, want: "15-25"},
|
|
{name: "scalar", input: `{"keepAlive":25}`, want: float64(25)},
|
|
{name: "explicit zero", input: `{"keepAlive":0}`, want: float64(0)},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var client Client
|
|
if err := json.Unmarshal([]byte(tt.input), &client); err != nil {
|
|
t.Fatalf("decode keepAlive: %v", err)
|
|
}
|
|
blob, err := json.Marshal(client)
|
|
if err != nil {
|
|
t.Fatalf("encode client: %v", err)
|
|
}
|
|
var got map[string]any
|
|
if err := json.Unmarshal(blob, &got); err != nil {
|
|
t.Fatalf("decode client output: %v", err)
|
|
}
|
|
if got["keepAlive"] != tt.want {
|
|
t.Fatalf("keepAlive JSON = %#v, want %#v", got["keepAlive"], tt.want)
|
|
}
|
|
})
|
|
}
|
|
|
|
var omitted Client
|
|
blob, err := json.Marshal(omitted)
|
|
if err != nil {
|
|
t.Fatalf("encode omitted client: %v", err)
|
|
}
|
|
var got map[string]any
|
|
if err := json.Unmarshal(blob, &got); err != nil {
|
|
t.Fatalf("decode omitted output: %v", err)
|
|
}
|
|
if _, ok := got["keepAlive"]; ok {
|
|
t.Fatalf("omitted keepAlive serialized as %#v", got["keepAlive"])
|
|
}
|
|
}
|
|
|
|
func TestKeepAliveValueValidatesNewInputAndPreservesLegacyScalar(t *testing.T) {
|
|
for _, value := range []KeepAliveValue{"0", "25", "65535"} {
|
|
if err := value.Validate(false); err != nil {
|
|
t.Errorf("scalar %q rejected: %v", value, err)
|
|
}
|
|
}
|
|
if err := KeepAliveValue("15-25").Validate(true); err != nil {
|
|
t.Fatalf("AmneziaWG range rejected: %v", err)
|
|
}
|
|
if err := KeepAliveValue("15-25").Validate(false); err == nil || err.Error() != "keepAlive ranges are supported only for AmneziaWG clients" {
|
|
t.Fatalf("WireGuard range error = %v", err)
|
|
}
|
|
for _, value := range []KeepAliveValue{"25-15", "0-65536", "65536", "01-2"} {
|
|
if err := value.Validate(true); err == nil {
|
|
t.Errorf("invalid new value %q accepted", value)
|
|
}
|
|
}
|
|
|
|
var legacy KeepAliveValue
|
|
if err := json.Unmarshal([]byte("70000"), &legacy); err != nil {
|
|
t.Fatalf("read legacy numeric value: %v", err)
|
|
}
|
|
blob, err := json.Marshal(legacy)
|
|
if err != nil {
|
|
t.Fatalf("marshal legacy numeric value: %v", err)
|
|
}
|
|
if string(blob) != "70000" {
|
|
t.Fatalf("legacy numeric value = %s, want 70000", blob)
|
|
}
|
|
if got := legacy.Seconds(); got != 70000 {
|
|
t.Fatalf("legacy scalar accessor = %d, want 70000", got)
|
|
}
|
|
if err := json.Unmarshal([]byte("-5"), &legacy); err != nil {
|
|
t.Fatalf("read legacy negative numeric value: %v", err)
|
|
}
|
|
blob, err = json.Marshal(legacy)
|
|
if err != nil || string(blob) != "-5" {
|
|
t.Fatalf("legacy negative numeric value = %s, %v; want -5", blob, err)
|
|
}
|
|
if err := legacy.Validate(true); err == nil {
|
|
t.Fatal("new-input validator accepted a legacy value above the panel bound")
|
|
}
|
|
if got := legacy.Seconds(); got != -5 {
|
|
t.Fatalf("legacy negative scalar accessor = %d, want -5", got)
|
|
}
|
|
}
|