Files

85 lines
3.1 KiB
Go

package api
import (
"testing"
"golang.org/x/crypto/bcrypt"
"vpn-platform/backend/internal/model"
"vpn-platform/backend/internal/store"
)
func TestClientSessionCannotExpandToSameNameOtherLine(t *testing.T) {
if err := store.Init(t.TempDir()); err != nil {
t.Fatal(err)
}
hashA, _ := bcrypt.GenerateFromPassword([]byte("password-a"), bcrypt.MinCost)
hashB, _ := bcrypt.GenerateFromPassword([]byte("password-b"), bcrypt.MinCost)
lineA := model.Tunnel{Name: "A", Protocol: "wireguard"}
lineB := model.Tunnel{Name: "B", Protocol: "wireguard"}
store.DB.Create(&lineA)
store.DB.Create(&lineB)
uA := model.VPNUser{TunnelID: lineA.ID, Username: "same", Password: string(hashA), Enabled: true, Source: "local"}
uB := model.VPNUser{TunnelID: lineB.ID, Username: "same", Password: string(hashB), Enabled: true, Source: "local"}
store.DB.Create(&uA)
store.DB.Create(&uB)
passed, _, err := authorizedLines("same", "password-a", "")
if err != nil || len(passed) != 1 || passed[0].ID != uA.ID {
t.Fatalf("错误的授权记录: %+v, %v", passed, err)
}
token, _, err := issueClientToken("same", "laptop", "linux", passed)
if err != nil {
t.Fatal(err)
}
var session model.ClientSession
if err := store.DB.Where("token_hash = ?", clientTokenHash(token)).First(&session).Error; err != nil {
t.Fatal(err)
}
granted := currentGrantedUsers(&session)
if _, _, err := clientAuthorizedTunnel(granted, lineB.ID); err == nil {
t.Fatal("错误密码的同名线路不得获得授权")
}
if _, _, err := clientAuthorizedTunnel(granted, lineA.ID); err != nil {
t.Fatal(err)
}
store.DB.Model(&uA).Update("password", string(hashB))
if got := currentGrantedUsers(&session); len(got) != 0 {
t.Fatalf("修改密码后旧授权必须失效: %+v", got)
}
}
func TestAllocateClientAddressSkipsUsedAndBoundaries(t *testing.T) {
used := map[string]bool{
"10.8.0.1": true, // 服务端自身
"10.8.0.2": true, // 已占用 Peer
}
addr, err := allocateClientAddress("10.8.0.1/24", used)
if err != nil {
t.Fatalf("allocate: %v", err)
}
if addr != "10.8.0.3/32" {
t.Fatalf("应分配第一个空闲地址 10.8.0.3/32,得到 %s", addr)
}
}
func TestAllocateClientAddressSmallSubnet(t *testing.T) {
// /30 只有 2 个可用主机位,均被占用时必须报错而不是返回网络/广播地址
used := map[string]bool{"10.8.0.1": true, "10.8.0.2": true}
if _, err := allocateClientAddress("10.8.0.1/30", used); err == nil {
t.Fatal("地址耗尽时必须报错")
}
if _, err := allocateClientAddress("10.8.0.1/31", map[string]bool{}); err == nil {
t.Fatal("/31 无可用主机位,必须报错")
}
if _, err := allocateClientAddress("fd00::1/64", map[string]bool{}); err == nil {
t.Fatal("IPv6 网段暂不支持自动分配,必须明确报错")
}
}
func TestAllocateClientAddressExhausted(t *testing.T) {
used := map[string]bool{"192.168.1.1": true, "192.168.1.2": true, "192.168.1.3": true,
"192.168.1.4": true, "192.168.1.5": true, "192.168.1.6": true}
if _, err := allocateClientAddress("192.168.1.1/29", used); err == nil {
t.Fatal("/29 全部占用时必须报错")
}
}