diff --git a/.gitignore b/.gitignore index fe5ec88..fbc8c5c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ development/ dist/ frontend/admin/reverse/node_modules/ log -sqldes \ No newline at end of file +sqldes +api.exe \ No newline at end of file diff --git a/internal/handler/admin_extra_api.go b/internal/handler/admin_extra_api.go index 48718ca..fde1a8b 100644 --- a/internal/handler/admin_extra_api.go +++ b/internal/handler/admin_extra_api.go @@ -207,7 +207,7 @@ func AdminUserResetSecret(c *gin.Context) { return } newUUID := uuid.NewString() - newToken := strings.ReplaceAll(uuid.NewString(), "-", "") + newToken := service.GenerateSubscriptionToken() if err := database.DB.Model(&model.User{}). Where("id = ?", payload.ID). Updates(map[string]any{"uuid": newUUID, "token": newToken}).Error; err != nil { diff --git a/internal/handler/auth_api.go b/internal/handler/auth_api.go index b1894ea..27e94f7 100644 --- a/internal/handler/auth_api.go +++ b/internal/handler/auth_api.go @@ -1,7 +1,6 @@ package handler import ( - "crypto/md5" "crypto/rand" "encoding/hex" "fmt" @@ -84,12 +83,11 @@ func Register(c *gin.Context) { } now := time.Now().Unix() - tokenRaw := fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String()+req.Email))) user := model.User{ Email: req.Email, Password: hashedPassword, UUID: uuid.New().String(), - Token: tokenRaw[:16], + Token: service.GenerateSubscriptionToken(), CreatedAt: now, UpdatedAt: now, } diff --git a/internal/handler/auth_handler.go b/internal/handler/auth_handler.go index 7dd2da5..cd19266 100644 --- a/internal/handler/auth_handler.go +++ b/internal/handler/auth_handler.go @@ -3,12 +3,11 @@ package handler import ( - "crypto/md5" - "fmt" "net/http" "time" "xboard-go/internal/database" "xboard-go/internal/model" + "xboard-go/internal/service" "xboard-go/pkg/utils" "github.com/gin-gonic/gin" @@ -21,8 +20,8 @@ type LoginRequest struct { } type RegisterRequest struct { - Email string `json:"email" binding:"required,email"` - Password string `json:"password" binding:"required,min=8"` + Email string `json:"email" binding:"required,email"` + Password string `json:"password" binding:"required,min=8"` InviteCode *string `json:"invite_code"` } @@ -51,7 +50,7 @@ func Login(c *gin.Context) { } c.JSON(http.StatusOK, gin.H{ - "token": token, + "token": token, "is_admin": user.IsAdmin, }) } @@ -78,9 +77,7 @@ func Register(c *gin.Context) { } newUUID := uuid.New().String() - // Generate a 16-character random token for compatibility - tokenRaw := fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String()+req.Email))) - token := tokenRaw[:16] + token := service.GenerateSubscriptionToken() user := model.User{ Email: req.Email, diff --git a/internal/handler/user_api.go b/internal/handler/user_api.go index e9ca55d..aeac7e3 100644 --- a/internal/handler/user_api.go +++ b/internal/handler/user_api.go @@ -115,7 +115,7 @@ func UserResetSecurity(c *gin.Context) { } newUUID := uuid.New().String() - newToken := fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String()+user.Email)))[:16] + newToken := service.GenerateSubscriptionToken() if err := database.DB.Model(&model.User{}). Where("id = ?", user.ID). Updates(map[string]any{"uuid": newUUID, "token": newToken, "updated_at": time.Now().Unix()}).Error; err != nil { diff --git a/internal/service/plugin.go b/internal/service/plugin.go index d34f03f..f0153a1 100644 --- a/internal/service/plugin.go +++ b/internal/service/plugin.go @@ -1,9 +1,7 @@ package service import ( - "crypto/md5" "encoding/json" - "fmt" "strconv" "strings" "time" @@ -101,7 +99,7 @@ func SyncIPv6ShadowAccount(user *model.User) bool { ipv6User.ID = 0 ipv6User.Email = ipv6Email ipv6User.UUID = uuid.New().String() - ipv6User.Token = fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String()+ipv6Email)))[:16] + ipv6User.Token = GenerateSubscriptionToken() ipv6User.U = 0 ipv6User.D = 0 ipv6User.T = 0 diff --git a/internal/service/token.go b/internal/service/token.go new file mode 100644 index 0000000..7c2faf2 --- /dev/null +++ b/internal/service/token.go @@ -0,0 +1,18 @@ +package service + +import ( + "crypto/rand" + "encoding/hex" +) + +// GenerateSubscriptionToken returns a 32-character hex token compatible with +// XBoard-style subscription URLs. +func GenerateSubscriptionToken() string { + buf := make([]byte, 16) + if _, err := rand.Read(buf); err != nil { + // Fall back to zero-value encoding only in the unlikely event random + // source fails; callers still get a stable-length token. + return hex.EncodeToString(buf) + } + return hex.EncodeToString(buf) +}