2025-12-03 10:58:39 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"net"
|
|
|
|
|
|
"regexp"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Validator Yggdrasil验证器
|
|
|
|
|
|
type Validator struct{}
|
|
|
|
|
|
|
|
|
|
|
|
// NewValidator 创建验证器实例
|
|
|
|
|
|
func NewValidator() *Validator {
|
|
|
|
|
|
return &Validator{}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
|
// emailRegex 邮箱正则表达式
|
|
|
|
|
|
emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateServerID 验证服务器ID格式
|
|
|
|
|
|
func (v *Validator) ValidateServerID(serverID string) error {
|
|
|
|
|
|
if serverID == "" {
|
|
|
|
|
|
return errors.New("服务器ID不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(serverID) > 100 {
|
|
|
|
|
|
return errors.New("服务器ID长度超过限制(最大100字符)")
|
|
|
|
|
|
}
|
|
|
|
|
|
// 防止注入攻击:检查危险字符
|
|
|
|
|
|
if strings.ContainsAny(serverID, "<>\"'&") {
|
|
|
|
|
|
return errors.New("服务器ID包含非法字符")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateIP 验证IP地址格式
|
|
|
|
|
|
func (v *Validator) ValidateIP(ip string) error {
|
|
|
|
|
|
if ip == "" {
|
|
|
|
|
|
return nil // IP是可选的
|
|
|
|
|
|
}
|
|
|
|
|
|
if net.ParseIP(ip) == nil {
|
|
|
|
|
|
return errors.New("IP地址格式无效")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateEmail 验证邮箱格式
|
|
|
|
|
|
func (v *Validator) ValidateEmail(email string) error {
|
|
|
|
|
|
if email == "" {
|
|
|
|
|
|
return errors.New("邮箱不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
if !emailRegex.MatchString(email) {
|
|
|
|
|
|
return errors.New("邮箱格式不正确")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-23 13:26:53 +08:00
|
|
|
|
// ValidateUUID 验证UUID格式(支持32位无符号和36位带连字符格式)
|
2025-12-03 10:58:39 +08:00
|
|
|
|
func (v *Validator) ValidateUUID(uuid string) error {
|
|
|
|
|
|
if uuid == "" {
|
|
|
|
|
|
return errors.New("UUID不能为空")
|
|
|
|
|
|
}
|
2026-02-23 13:26:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 验证32位无符号UUID格式(纯十六进制字符串)
|
|
|
|
|
|
if len(uuid) == 32 {
|
|
|
|
|
|
// 检查是否为有效的十六进制字符串
|
|
|
|
|
|
for _, c := range uuid {
|
|
|
|
|
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
|
|
|
|
|
return errors.New("UUID格式无效:包含非十六进制字符")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
2025-12-03 10:58:39 +08:00
|
|
|
|
}
|
2026-02-23 13:26:53 +08:00
|
|
|
|
|
|
|
|
|
|
// 验证36位标准UUID格式(带连字符)
|
|
|
|
|
|
if len(uuid) == 36 && uuid[8] == '-' && uuid[13] == '-' && uuid[18] == '-' && uuid[23] == '-' {
|
|
|
|
|
|
// 检查除连字符外的字符是否为有效的十六进制
|
|
|
|
|
|
for i, c := range uuid {
|
|
|
|
|
|
if i == 8 || i == 13 || i == 18 || i == 23 {
|
|
|
|
|
|
continue // 跳过连字符位置
|
|
|
|
|
|
}
|
|
|
|
|
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
|
|
|
|
|
return errors.New("UUID格式无效:包含非十六进制字符")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return errors.New("UUID格式无效:长度应为32位或36位")
|
2025-12-03 10:58:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ValidateAccessToken 验证访问令牌
|
|
|
|
|
|
func (v *Validator) ValidateAccessToken(token string) error {
|
|
|
|
|
|
if token == "" {
|
|
|
|
|
|
return errors.New("访问令牌不能为空")
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(token) < 10 {
|
|
|
|
|
|
return errors.New("访问令牌格式无效")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|