mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
1.8 KiB
Go
73 lines
1.8 KiB
Go
//
|
|
// validate.go
|
|
// Copyright (C) 2025 veypi <i@veypi.com>
|
|
//
|
|
// Distributed under terms of the MIT license.
|
|
//
|
|
|
|
package sms
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/veypi/OneAuth/cfg"
|
|
"github.com/veypi/OneAuth/libs/utils"
|
|
"github.com/veypi/OneAuth/models"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// VerifyCode 验证验证码
|
|
func VerifyCode(Phone, Code, Region, Purpose string) error {
|
|
normalizedPhone := utils.NormalizePhoneNumber(Phone)
|
|
|
|
// 1. 查找最新的待验证码
|
|
var smsCode models.SMSCode
|
|
err := cfg.DB().Where("phone = ? AND region = ? AND purpose = ? AND status = ?",
|
|
normalizedPhone, Region, Purpose, models.CodeStatusPending).
|
|
Order("created_at DESC").
|
|
First(&smsCode).Error
|
|
|
|
if err != nil {
|
|
if err == gorm.ErrRecordNotFound {
|
|
return fmt.Errorf("verification code not found or already used")
|
|
}
|
|
return fmt.Errorf("failed to query sms code: %w", err)
|
|
}
|
|
|
|
// 2. 检查验证码是否过期
|
|
if smsCode.IsExpired() {
|
|
cfg.DB().Model(&smsCode).Updates(map[string]any{
|
|
"status": models.CodeStatusExpired,
|
|
})
|
|
return fmt.Errorf("verification code has expired")
|
|
}
|
|
|
|
// 3. 检查是否已达到最大尝试次数
|
|
if !smsCode.CanRetry(cfg.Config.SMS.Global.MaxAttempts) {
|
|
cfg.DB().Model(&smsCode).Updates(map[string]any{
|
|
"status": models.CodeStatusFailed,
|
|
})
|
|
return fmt.Errorf("verification failed too many times")
|
|
}
|
|
|
|
// 4. 验证码不匹配
|
|
if smsCode.Code != Code {
|
|
cfg.DB().Model(&smsCode).Updates(map[string]any{
|
|
"attempts": smsCode.Attempts + 1,
|
|
})
|
|
|
|
remaining := cfg.Config.SMS.Global.MaxAttempts - smsCode.Attempts - 1
|
|
return fmt.Errorf("verification code incorrect, %d attempts remaining", remaining)
|
|
}
|
|
|
|
// 5. 验证成功
|
|
now := time.Now()
|
|
cfg.DB().Model(&smsCode).Updates(map[string]any{
|
|
"status": models.CodeStatusUsed,
|
|
"used_at": &now,
|
|
})
|
|
|
|
return nil
|
|
}
|