121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
|
package accountlogic
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/rand"
|
||
|
"fmt"
|
||
|
"math/big"
|
||
|
"strconv"
|
||
|
|
||
|
ers "code.30cm.net/digimon/library-go/errors"
|
||
|
|
||
|
"app-cloudep-member-server/gen_result/pb/member"
|
||
|
"app-cloudep-member-server/internal/svc"
|
||
|
|
||
|
"github.com/zeromicro/go-zero/core/logx"
|
||
|
)
|
||
|
|
||
|
type GenerateRefreshCodeLogic struct {
|
||
|
ctx context.Context
|
||
|
svcCtx *svc.ServiceContext
|
||
|
logx.Logger
|
||
|
}
|
||
|
|
||
|
func NewGenerateRefreshCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GenerateRefreshCodeLogic {
|
||
|
return &GenerateRefreshCodeLogic{
|
||
|
ctx: ctx,
|
||
|
svcCtx: svcCtx,
|
||
|
Logger: logx.WithContext(ctx),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type generateRefreshCodeReq struct {
|
||
|
Account string `json:"account" validate:"account"`
|
||
|
// CodeType 1 register_email, 2 register_phone, 3 forget_email
|
||
|
CodeType int32 `json:"code_type" validate:"required,oneof=1 2 3"`
|
||
|
}
|
||
|
|
||
|
// GenerateRefreshCode 這個帳號驗證碼(十分鐘),通用的
|
||
|
func (l *GenerateRefreshCodeLogic) GenerateRefreshCode(in *member.GenerateRefreshCodeReq) (*member.GenerateRefreshCodeResp, error) {
|
||
|
// 驗證資料
|
||
|
if err := l.svcCtx.Validate.ValidateAll(&generateRefreshCodeReq{
|
||
|
Account: in.GetAccount(),
|
||
|
CodeType: in.GetCodeType(),
|
||
|
}); err != nil {
|
||
|
return nil, ers.InvalidFormat(err.Error())
|
||
|
}
|
||
|
|
||
|
checkType, status := getCodeNameByCode(in.GetCodeType())
|
||
|
if !status {
|
||
|
return nil, ers.InvalidFormat(fmt.Errorf("failed to get correct code type").Error())
|
||
|
}
|
||
|
rk := fmt.Sprintf("verify:%s:%s", checkType, in.GetAccount())
|
||
|
// 拿過就不要再拿了
|
||
|
get, err := l.svcCtx.Redis.Get(rk)
|
||
|
if err != nil {
|
||
|
return nil, ers.DBError("failed to connect to redis", err.Error())
|
||
|
}
|
||
|
if get != "" {
|
||
|
return &member.GenerateRefreshCodeResp{
|
||
|
Data: &member.VerifyCode{
|
||
|
VerifyCode: get,
|
||
|
},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
code, err := generateVerifyCode(6)
|
||
|
if !status {
|
||
|
return nil, ers.ArkInternal(err.Error())
|
||
|
}
|
||
|
|
||
|
err = l.svcCtx.Redis.Setex(rk, code, 600)
|
||
|
if err != nil {
|
||
|
return nil, ers.ArkInternal(err.Error())
|
||
|
}
|
||
|
|
||
|
return &member.GenerateRefreshCodeResp{
|
||
|
Data: &member.VerifyCode{
|
||
|
VerifyCode: code,
|
||
|
},
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
var codeMap = map[int32]string{
|
||
|
1: "email",
|
||
|
2: "phone",
|
||
|
3: "forget_email",
|
||
|
}
|
||
|
|
||
|
func getCodeNameByCode(code int32) (string, bool) {
|
||
|
res, ok := codeMap[code]
|
||
|
if !ok {
|
||
|
return "", false
|
||
|
}
|
||
|
|
||
|
return res, true
|
||
|
}
|
||
|
|
||
|
func generateVerifyCode(digits int) (string, error) {
|
||
|
if digits <= 0 {
|
||
|
// 預設為六位數
|
||
|
digits = 6
|
||
|
}
|
||
|
|
||
|
// 計算最大值 (10^digits - 1)
|
||
|
exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(digits)), nil)
|
||
|
// 生成隨機數
|
||
|
randomNumber, err := rand.Int(rand.Reader, exp)
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
// 將隨機數轉換為 string
|
||
|
verifyCode := strconv.Itoa(int(randomNumber.Int64()))
|
||
|
// 如果隨機數的位數少於指定的位數,則補 0
|
||
|
if len(verifyCode) < digits {
|
||
|
verifyCode = fmt.Sprintf("%0*d", digits, randomNumber)
|
||
|
}
|
||
|
|
||
|
return verifyCode, nil
|
||
|
}
|