151 lines
4.3 KiB
Go
151 lines
4.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"math"
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"go-common/app/interface/main/answer/model"
|
|
"go-common/library/log"
|
|
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
// preProcess getGeetestChal
|
|
func (s *Service) preProcess(c context.Context, mid int64, ip, clientType string, newCaptcha int) (res *model.ProcessRes, err error) {
|
|
var pre string
|
|
res = &model.ProcessRes{}
|
|
gc, geeType := s.geetestDao.GeeConfig(clientType, s.c.Geetest)
|
|
res.CaptchaID = gc.CaptchaID
|
|
res.NewCaptcha = newCaptcha
|
|
if pre, err = s.geetestDao.PreProcess(c, mid, ip, geeType, gc, newCaptcha); err != nil || pre == "" {
|
|
log.Error("s.geetestDao.PreProcess(%d) err(%v)", mid, err)
|
|
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
|
|
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
|
|
challenge := hex.EncodeToString(randOne[:]) + hex.EncodeToString(randTwo[:])[0:2]
|
|
res.Challenge = challenge
|
|
err = nil
|
|
return
|
|
}
|
|
res.Success = 1
|
|
slice := md5.Sum([]byte(pre + gc.PrivateKEY))
|
|
res.Challenge = hex.EncodeToString(slice[:])
|
|
return
|
|
}
|
|
|
|
// validate recheck the seccode
|
|
func (s *Service) validate(c context.Context, challenge, validate, seccode, clientType, ip string, success int, mid int64) (stat bool) {
|
|
if len(validate) != 32 {
|
|
log.Error("s.Validate(%s,%s,%s,%d) err(validate not eq 32byte)", challenge, validate, seccode, mid)
|
|
stat = s.failbackValidate(c, challenge, validate, seccode)
|
|
log.Info("s.failbackValidate(%s,%s,%s,%d), stat(%t)", challenge, validate, seccode, mid, stat)
|
|
return
|
|
}
|
|
if success != 1 {
|
|
slice := md5.Sum([]byte(challenge))
|
|
stat = hex.EncodeToString(slice[:]) == validate
|
|
return
|
|
}
|
|
gc, geeType := s.geetestDao.GeeConfig(clientType, s.c.Geetest)
|
|
slice := md5.Sum([]byte(gc.PrivateKEY + "geetest" + challenge))
|
|
if hex.EncodeToString(slice[:]) != validate {
|
|
log.Error("s.Validate(%s,%s,%s,%d) err(challenge not found)", challenge, validate, seccode, mid)
|
|
return
|
|
}
|
|
res, err := s.geetestDao.Validate(c, challenge, seccode, geeType, ip, gc.CaptchaID, mid)
|
|
if err != nil {
|
|
if errors.Cause(err) == context.DeadlineExceeded { // for geetest timeout
|
|
stat = true
|
|
return
|
|
}
|
|
log.Error("s.geetestDao.Validate(%d) err(%v)", mid, err)
|
|
return
|
|
}
|
|
slice = md5.Sum([]byte(seccode))
|
|
stat = hex.EncodeToString(slice[:]) == res.Seccode
|
|
return
|
|
}
|
|
|
|
//failbackValidate geetest failback model.
|
|
func (s *Service) failbackValidate(c context.Context, challenge, validate, seccode string) bool {
|
|
varr := strings.Split(validate, "_")
|
|
if len(varr) < 3 {
|
|
return false
|
|
}
|
|
encodeAns := varr[0]
|
|
encodeFbii := varr[1]
|
|
encodeIgi := varr[2]
|
|
decodeAns := s.decodeResponse(challenge, encodeAns)
|
|
decodeFbii := s.decodeResponse(challenge, encodeFbii)
|
|
decodeIgi := s.decodeResponse(challenge, encodeIgi)
|
|
return s.validateFailImage(decodeAns, decodeFbii, decodeIgi)
|
|
}
|
|
|
|
func (s *Service) decodeResponse(challenge, userresponse string) (res int) {
|
|
if len(userresponse) > 100 {
|
|
return
|
|
}
|
|
digits := []int{1, 2, 5, 10, 50}
|
|
key := make(map[rune]int)
|
|
for _, i := range challenge {
|
|
if _, exist := key[i]; exist {
|
|
continue
|
|
}
|
|
value := digits[len(key)%5]
|
|
key[i] = value
|
|
}
|
|
for _, i := range userresponse {
|
|
res += key[i]
|
|
}
|
|
res -= s.decodeRandBase(challenge)
|
|
return
|
|
}
|
|
|
|
func (s *Service) decodeRandBase(challenge string) int {
|
|
baseStr := challenge[32:]
|
|
var tempList []int
|
|
for _, char := range baseStr {
|
|
tempChar := int(char)
|
|
result := tempChar - 48
|
|
if tempChar > 57 {
|
|
result = tempChar - 87
|
|
}
|
|
tempList = append(tempList, result)
|
|
}
|
|
return tempList[0]*36 + tempList[1]
|
|
}
|
|
|
|
func (s *Service) md5Encode(values []byte) string {
|
|
return fmt.Sprintf("%x", md5.Sum(values))
|
|
}
|
|
|
|
func (s *Service) validateFailImage(ans, fullBgIndex, imgGrpIndex int) bool {
|
|
var thread float64 = 3
|
|
fullBg := s.md5Encode([]byte(strconv.Itoa(fullBgIndex)))[0:10]
|
|
imgGrp := s.md5Encode([]byte(strconv.Itoa(imgGrpIndex)))[10:20]
|
|
var answerDecode []byte
|
|
for i := 0; i < 9; i++ {
|
|
if i%2 == 0 {
|
|
answerDecode = append(answerDecode, fullBg[i])
|
|
} else if i%2 == 1 {
|
|
answerDecode = append(answerDecode, imgGrp[i])
|
|
}
|
|
}
|
|
xDecode := answerDecode[4:]
|
|
xInt64, err := strconv.ParseInt(string(xDecode), 16, 32)
|
|
if err != nil {
|
|
log.Error("%+v", err)
|
|
}
|
|
xInt := int(xInt64)
|
|
result := xInt % 200
|
|
if result < 40 {
|
|
result = 40
|
|
}
|
|
return math.Abs(float64(ans-result)) < thread
|
|
}
|