package wireguard import ( "encoding/json" "os" "strconv" "strings" "testing" "vpn-platform/backend/internal/model" "vpn-platform/backend/internal/store" ) func TestBuildPeersMigratesLegacySingleClient(t *testing.T) { cfg := map[string]interface{}{ "address": "10.8.0.1/24", "client_address": "10.8.0.2/32", "allowed_ips": "0.0.0.0/0, ::/0", } peers, secrets, err := buildPeers(cfg, map[string]interface{}{}) if err != nil { t.Fatalf("buildPeers: %v", err) } if len(peers) != 1 || peers[0].ID != "client-1" || !peers[0].Managed { t.Fatalf("legacy peer migration = %#v", peers) } if !isWireGuardKey(peers[0].PublicKey) || !isWireGuardKey(secrets["client-1"].PrivateKey) || !isWireGuardKey(secrets["client-1"].PresharedKey) { t.Fatal("generated peer keys are not WireGuard keys") } cfg["server_public_key"] = "server-public-key" cfg["listen_port"] = 51820 client, err := generateClientConfig(cfg, peers, secrets, "client-1") if err != nil { t.Fatalf("generateClientConfig: %v", err) } if !strings.Contains(client, "Address = 10.8.0.2/32") || !strings.Contains(client, "Endpoint = your-server-ip:51820") { t.Fatalf("unexpected client config:\n%s", client) } } func TestBuildPeersKeepsExternalPeerPrivateKeyOutOfPlatform(t *testing.T) { _, externalPublic, err := genKey() if err != nil { t.Fatal(err) } cfg := map[string]interface{}{ "allowed_ips": "10.0.0.0/8", "peers": []interface{}{map[string]interface{}{ "id": "branch-office", "name": "Branch office", "public_key": externalPublic, "client_address": "10.8.0.10/32", "enabled": true, }}, } peers, secrets, err := buildPeers(cfg, map[string]interface{}{}) if err != nil { t.Fatalf("buildPeers: %v", err) } if peers[0].Managed || secrets["branch-office"].PrivateKey != "" { t.Fatalf("external peer must not gain a platform-held private key: %#v %#v", peers[0], secrets["branch-office"]) } if _, err := generateClientConfig(cfg, peers, secrets, "branch-office"); err == nil { t.Fatal("external peer configuration should not be downloadable") } } func TestValidateRejectsUnsafeNATAndInvalidPeerAddress(t *testing.T) { s := New() if _, err := s.Validate(map[string]interface{}{"address": "10.8.0.1/24", "enable_nat": true}); err == nil { t.Fatal("NAT without explicit egress interface was accepted") } _, err := s.Validate(map[string]interface{}{ "address": "10.8.0.1/24", "peers": []interface{}{map[string]interface{}{"id": "bad", "client_address": "not-a-cidr"}}, }) if err == nil { t.Fatal("invalid peer address was accepted") } } func TestInterfaceNameFitsLinuxLimit(t *testing.T) { name := interfaceName(&model.Tunnel{ID: ^uint(0)}) if len(name) > 15 { t.Fatalf("interface name %q exceeds IFNAMSIZ-1", name) } } func TestCreatePersistsOnlyPublicPeerData(t *testing.T) { dataDir := t.TempDir() t.Setenv("VPN_DATA_DIR", dataDir) if err := store.Init(dataDir); err != nil { t.Fatalf("store.Init: %v", err) } tunnel := &model.Tunnel{ Name: "wg-test", Protocol: "wireguard", Config: `{"address":"10.60.0.1/24","client_address":"10.60.0.2/32"}`, } if err := store.DB.Create(tunnel).Error; err != nil { t.Fatal(err) } if err := New().Create(tunnel); err != nil { t.Fatalf("Create: %v", err) } if strings.Contains(tunnel.Config, "private_key") || strings.Contains(tunnel.Config, "preshared_key") { t.Fatalf("private material leaked into Config: %s", tunnel.Config) } var config map[string]interface{} if err := json.Unmarshal([]byte(tunnel.Config), &config); err != nil { t.Fatal(err) } if config["interface_name"] != interfaceName(tunnel) || int(config["listen_port"].(float64)) < defaultPort { t.Fatalf("missing interface/allocated port: %#v", config) } conf, err := New().GenerateClientConfig(tunnel) if err != nil || !strings.Contains(conf, "PrivateKey = ") { t.Fatalf("client configuration unavailable: %v\n%s", err, conf) } if _, err := os.Stat(serviceConfigPath(tunnel)); err != nil { t.Fatalf("server config not written: %v", err) } } func serviceConfigPath(tunnel *model.Tunnel) string { return os.Getenv("VPN_DATA_DIR") + "/instances/" + strconv.Itoa(int(tunnel.ID)) + "-" + tunnel.Protocol + "/" + interfaceName(tunnel) + ".conf" }