From 3d51aa455006903345f554a2dd90034993796114 Mon Sep 17 00:00:00 2001 From: sergei Date: Tue, 14 Apr 2026 06:23:55 +0400 Subject: vpnem: VPN infrastructure with load-balanced multi-protocol nodes - Multi-protocol VPS nodes (VLESS-REALITY + Hysteria2 + SOCKS5) - Smart load balancing via recommendation API - Windows/Linux client (Go + Wails + sing-box) - Server API with RealIP detection and connection tracking - Auto-deployment via vpnui control plane - Silent Windows installer with UAC elevation - Load-based server recommendation (no sticky sessions) - Best Server one-click connection workflow --- internal/control/ssh_test.go | 80 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 internal/control/ssh_test.go (limited to 'internal/control/ssh_test.go') diff --git a/internal/control/ssh_test.go b/internal/control/ssh_test.go new file mode 100644 index 0000000..8b7afd0 --- /dev/null +++ b/internal/control/ssh_test.go @@ -0,0 +1,80 @@ +package control + +import ( + "context" + "os" + "path/filepath" + "testing" +) + +func TestValidateNodeSSHPasswordAuth(t *testing.T) { + t.Parallel() + + node := Node{ + ID: "pw-01", + Name: "Password Node", + Provider: "custom-vps", + Region: "nl", + Host: "203.0.113.20", + Enabled: true, + SSH: SSHConfig{ + User: "root", + Port: 22, + Auth: "password", + PasswordEnv: "VPNEM_TEST_PASSWORD", + }, + Protocols: []ProtocolProfile{ + {Type: "socks5", Enabled: true, Port: 1080}, + }, + } + + if err := ValidateNode(node); err != nil { + t.Fatalf("ValidateNode() error = %v", err) + } +} + +func TestWrapWithPasswordUsesSSHPass(t *testing.T) { + t.Setenv("VPNEM_TEST_PASSWORD", "secret") + node := Node{ + ID: "pw-01", + Name: "Password Node", + SSH: SSHConfig{ + User: "root", + Port: 22, + Auth: "password", + PasswordEnv: "VPNEM_TEST_PASSWORD", + }, + } + + cmd, err := wrapWithPassword(context.Background(), node, "ssh", "-V") + if err != nil { + t.Fatalf("wrapWithPassword() error = %v", err) + } + if got := filepath.Base(cmd.Path); got != "sshpass" { + t.Fatalf("filepath.Base(cmd.Path) = %q, want sshpass", got) + } + if len(cmd.Args) < 4 { + t.Fatalf("cmd.Args too short: %#v", cmd.Args) + } + if cmd.Args[1] != "-p" || cmd.Args[2] != "secret" || cmd.Args[3] != "ssh" { + t.Fatalf("unexpected cmd.Args: %#v", cmd.Args) + } +} + +func TestWrapWithPasswordRequiresEnv(t *testing.T) { + _ = os.Unsetenv("VPNEM_TEST_PASSWORD_MISSING") + node := Node{ + ID: "pw-01", + Name: "Password Node", + SSH: SSHConfig{ + User: "root", + Port: 22, + Auth: "password", + PasswordEnv: "VPNEM_TEST_PASSWORD_MISSING", + }, + } + + if _, err := wrapWithPassword(context.Background(), node, "ssh", "-V"); err == nil { + t.Fatal("expected error for missing password env") + } +} -- cgit v1.2.3