You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cloudreve/middleware/captcha.go

128 lines
3.8 KiB

package middleware
import (
"bytes"
"encoding/json"
model "github.com/cloudreve/Cloudreve/v3/models"
"github.com/cloudreve/Cloudreve/v3/pkg/recaptcha"
"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
"github.com/gin-gonic/gin"
"github.com/mojocn/base64Captcha"
captcha "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/captcha/v20190722"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
"io"
"io/ioutil"
"strconv"
"time"
)
type req struct {
CaptchaCode string `json:"captchaCode"`
Ticket string `json:"ticket"`
Randstr string `json:"randstr"`
}
const (
captchaNotMatch = "CAPTCHA not match."
captchaRefresh = "Verification failed, please refresh the page and retry."
)
// CaptchaRequired 验证请求签名
func CaptchaRequired(configName string) gin.HandlerFunc {
return func(c *gin.Context) {
// 相关设定
options := model.GetSettingByNames(configName,
"captcha_type",
"captcha_ReCaptchaSecret",
"captcha_TCaptcha_SecretId",
"captcha_TCaptcha_SecretKey",
"captcha_TCaptcha_CaptchaAppId",
"captcha_TCaptcha_AppSecretKey")
// 检查验证码
isCaptchaRequired := model.IsTrueVal(options[configName])
if isCaptchaRequired {
var service req
bodyCopy := new(bytes.Buffer)
_, err := io.Copy(bodyCopy, c.Request.Body)
if err != nil {
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
c.Abort()
return
}
bodyData := bodyCopy.Bytes()
err = json.Unmarshal(bodyData, &service)
if err != nil {
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
c.Abort()
return
}
c.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyData))
switch options["captcha_type"] {
case "normal":
captchaID := util.GetSession(c, "captchaID")
util.DeleteSession(c, "captchaID")
if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
c.Abort()
return
}
break
case "recaptcha":
reCAPTCHA, err := recaptcha.NewReCAPTCHA(options["captcha_ReCaptchaSecret"], recaptcha.V2, 10*time.Second)
if err != nil {
util.Log().Warning("reCAPTCHA verification failed, %s", err)
c.Abort()
break
}
err = reCAPTCHA.Verify(service.CaptchaCode)
if err != nil {
util.Log().Warning("reCAPTCHA verification failed, %s", err)
c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
c.Abort()
return
}
break
case "tcaptcha":
credential := common.NewCredential(
options["captcha_TCaptcha_SecretId"],
options["captcha_TCaptcha_SecretKey"],
)
cpf := profile.NewClientProfile()
cpf.HttpProfile.Endpoint = "captcha.tencentcloudapi.com"
client, _ := captcha.NewClient(credential, "", cpf)
request := captcha.NewDescribeCaptchaResultRequest()
request.CaptchaType = common.Uint64Ptr(9)
appid, _ := strconv.Atoi(options["captcha_TCaptcha_CaptchaAppId"])
request.CaptchaAppId = common.Uint64Ptr(uint64(appid))
request.AppSecretKey = common.StringPtr(options["captcha_TCaptcha_AppSecretKey"])
request.Ticket = common.StringPtr(service.Ticket)
request.Randstr = common.StringPtr(service.Randstr)
request.UserIp = common.StringPtr(c.ClientIP())
response, err := client.DescribeCaptchaResult(request)
if err != nil {
util.Log().Warning("TCaptcha verification failed, %s", err)
c.Abort()
break
}
if *response.Response.CaptchaCode != int64(1) {
c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
c.Abort()
return
}
break
}
}
c.Next()
}
}