- Add YggdrasilErrorResponse struct and standard error codes for protocol compliance - Change UUID storage from varchar(36) to varchar(32) for unsigned format - Add utility functions: GenerateUUID, FormatUUIDToNoDash, RandomHex - Support unsigned query parameter in GetProfileByUUID endpoint - Improve refresh token response with available profiles list - Fix key pair retrieval to use correct database column (rsa_private_key) - Update UUID validator to accept both 32-char and 36-char formats - Add SignStringWithProfileRSA method for profile-specific signing - Fix profile assignment validation in refresh token flow
104 lines
2.6 KiB
Go
104 lines
2.6 KiB
Go
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
|
||
}
|
||
|
||
// ValidateUUID 验证UUID格式(支持32位无符号和36位带连字符格式)
|
||
func (v *Validator) ValidateUUID(uuid string) error {
|
||
if uuid == "" {
|
||
return errors.New("UUID不能为空")
|
||
}
|
||
|
||
// 验证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
|
||
}
|
||
|
||
// 验证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位")
|
||
}
|
||
|
||
// ValidateAccessToken 验证访问令牌
|
||
func (v *Validator) ValidateAccessToken(token string) error {
|
||
if token == "" {
|
||
return errors.New("访问令牌不能为空")
|
||
}
|
||
if len(token) < 10 {
|
||
return errors.New("访问令牌格式无效")
|
||
}
|
||
return nil
|
||
}
|