|
|
package geetest
|
|
|
|
|
|
import (
|
|
|
"crypto/md5"
|
|
|
"encoding/hex"
|
|
|
"encoding/json"
|
|
|
"errors"
|
|
|
"io/ioutil"
|
|
|
"net/http"
|
|
|
"net/url"
|
|
|
"strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
type GeetestLib struct {
|
|
|
CaptchaID string
|
|
|
PrivateKey string
|
|
|
Client *http.Client
|
|
|
}
|
|
|
|
|
|
type FailbackRegisterRespnse struct {
|
|
|
Success int `json:"success"`
|
|
|
GT string `json:"gt"`
|
|
|
Challenge string `json:"challenge"`
|
|
|
NewCaptcha int `json:"new_captcha"`
|
|
|
}
|
|
|
|
|
|
const (
|
|
|
geetestHost = "http://api.geetest.com"
|
|
|
registerURL = geetestHost + "/register.php"
|
|
|
validateURL = geetestHost + "/validate.php"
|
|
|
)
|
|
|
|
|
|
func MD5Encode(input string) string {
|
|
|
md5Instant := md5.New()
|
|
|
md5Instant.Write([]byte(input))
|
|
|
return hex.EncodeToString(md5Instant.Sum(nil))
|
|
|
}
|
|
|
|
|
|
// 初始化 GeetestLib
|
|
|
func NewGeetestLib(capthcaID string, privateKey string, timeOut time.Duration) (geetest GeetestLib){
|
|
|
client := &http.Client{Timeout: timeOut}
|
|
|
geetest = GeetestLib{capthcaID, privateKey, client}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) getFailBackRegisterResponse(success int, challenge string) []byte {
|
|
|
if challenge == "" {
|
|
|
challenge = hex.EncodeToString(md5.New().Sum(nil))
|
|
|
}
|
|
|
|
|
|
response := FailbackRegisterRespnse{
|
|
|
success,
|
|
|
g.CaptchaID,
|
|
|
challenge,
|
|
|
1,
|
|
|
}
|
|
|
res, _ := json.Marshal(response)
|
|
|
return res
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) do(req *http.Request) (body []byte, err error) {
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
var resp *http.Response
|
|
|
if resp, err = g.Client.Do(req); err != nil {
|
|
|
return
|
|
|
}
|
|
|
defer resp.Body.Close()
|
|
|
if resp.StatusCode >= http.StatusInternalServerError {
|
|
|
err = errors.New("http status code 5xx")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
if body, err = ioutil.ReadAll(resp.Body); err != nil {
|
|
|
return
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) PreProcess(userID string, userIP string) (int8, []byte) {
|
|
|
params := url.Values{}
|
|
|
params.Add("gt", g.CaptchaID)
|
|
|
params.Add("new_captcha", "1")
|
|
|
if userID != "" {
|
|
|
params.Add("user_id", userID)
|
|
|
}
|
|
|
if userIP != "" {
|
|
|
params.Add("ip_adress", userIP)
|
|
|
}
|
|
|
req, _ := http.NewRequest("GET", registerURL+"?"+params.Encode(), nil)
|
|
|
body, err := g.do(req)
|
|
|
if err != nil {
|
|
|
return 0, g.getFailBackRegisterResponse(0, "")
|
|
|
}
|
|
|
challenge := string(body)
|
|
|
if len(challenge) != 32 {
|
|
|
return 0, g.getFailBackRegisterResponse(0, "")
|
|
|
} else {
|
|
|
challenge = MD5Encode(challenge + g.PrivateKey)
|
|
|
return 1, g.getFailBackRegisterResponse(1, challenge)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) checkParas(challenge string, validate string, seccode string) bool {
|
|
|
if challenge == "" || validate == "" || seccode == "" {
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) checkSuccessRes(challenge string, validate string) bool {
|
|
|
return MD5Encode(g.PrivateKey+"geetest"+challenge) == validate
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) checkFailbackRes(challenge string, validate string) bool {
|
|
|
return MD5Encode(challenge) == validate
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) SuccessValidate(challenge string, validate string, seccode string, userID string, userIP string) bool {
|
|
|
if !g.checkParas(challenge, validate, seccode) {
|
|
|
return false
|
|
|
}
|
|
|
if !g.checkSuccessRes(challenge, validate) {
|
|
|
return false
|
|
|
}
|
|
|
params := url.Values{}
|
|
|
params.Add("seccode", seccode)
|
|
|
params.Add("challenge", challenge)
|
|
|
params.Add("captchaid", g.CaptchaID)
|
|
|
params.Add("sdk", "golang_v1.0.0")
|
|
|
if userID != "" {
|
|
|
params.Add("user_id", userID)
|
|
|
}
|
|
|
if userIP != "" {
|
|
|
params.Add("ip_adress", userIP)
|
|
|
}
|
|
|
req, _ := http.NewRequest("POST", validateURL, strings.NewReader(params.Encode()))
|
|
|
body, err := g.do(req)
|
|
|
if err != nil {
|
|
|
return false
|
|
|
}
|
|
|
res := string(body)
|
|
|
return res == MD5Encode(seccode)
|
|
|
}
|
|
|
|
|
|
func (g *GeetestLib) FailbackValidate(challenge string, validate string, seccode string) bool {
|
|
|
if !g.checkParas(challenge, validate, seccode) {
|
|
|
return false
|
|
|
}
|
|
|
if !g.checkFailbackRes(challenge, validate) {
|
|
|
return false
|
|
|
}
|
|
|
return true
|
|
|
} |
...
|
...
|
|