github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/middleware/captcha.go (about)

     1  package middleware
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	model "github.com/cloudreve/Cloudreve/v3/models"
     7  	"github.com/cloudreve/Cloudreve/v3/pkg/recaptcha"
     8  	"github.com/cloudreve/Cloudreve/v3/pkg/serializer"
     9  	"github.com/cloudreve/Cloudreve/v3/pkg/util"
    10  	"github.com/gin-gonic/gin"
    11  	"github.com/mojocn/base64Captcha"
    12  	captcha "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/captcha/v20190722"
    13  	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
    14  	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
    15  	"io"
    16  	"io/ioutil"
    17  	"strconv"
    18  	"time"
    19  )
    20  
    21  type req struct {
    22  	CaptchaCode string `json:"captchaCode"`
    23  	Ticket      string `json:"ticket"`
    24  	Randstr     string `json:"randstr"`
    25  }
    26  
    27  const (
    28  	captchaNotMatch = "CAPTCHA not match."
    29  	captchaRefresh  = "Verification failed, please refresh the page and retry."
    30  )
    31  
    32  // CaptchaRequired 验证请求签名
    33  func CaptchaRequired(configName string) gin.HandlerFunc {
    34  	return func(c *gin.Context) {
    35  		// 相关设定
    36  		options := model.GetSettingByNames(configName,
    37  			"captcha_type",
    38  			"captcha_ReCaptchaSecret",
    39  			"captcha_TCaptcha_SecretId",
    40  			"captcha_TCaptcha_SecretKey",
    41  			"captcha_TCaptcha_CaptchaAppId",
    42  			"captcha_TCaptcha_AppSecretKey")
    43  		// 检查验证码
    44  		isCaptchaRequired := model.IsTrueVal(options[configName])
    45  
    46  		if isCaptchaRequired {
    47  			var service req
    48  			bodyCopy := new(bytes.Buffer)
    49  			_, err := io.Copy(bodyCopy, c.Request.Body)
    50  			if err != nil {
    51  				c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
    52  				c.Abort()
    53  				return
    54  			}
    55  
    56  			bodyData := bodyCopy.Bytes()
    57  			err = json.Unmarshal(bodyData, &service)
    58  			if err != nil {
    59  				c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
    60  				c.Abort()
    61  				return
    62  			}
    63  
    64  			c.Request.Body = ioutil.NopCloser(bytes.NewReader(bodyData))
    65  			switch options["captcha_type"] {
    66  			case "normal":
    67  				captchaID := util.GetSession(c, "captchaID")
    68  				util.DeleteSession(c, "captchaID")
    69  				if captchaID == nil || !base64Captcha.VerifyCaptcha(captchaID.(string), service.CaptchaCode) {
    70  					c.JSON(200, serializer.Err(serializer.CodeCaptchaError, captchaNotMatch, err))
    71  					c.Abort()
    72  					return
    73  				}
    74  
    75  				break
    76  			case "recaptcha":
    77  				reCAPTCHA, err := recaptcha.NewReCAPTCHA(options["captcha_ReCaptchaSecret"], recaptcha.V2, 10*time.Second)
    78  				if err != nil {
    79  					util.Log().Warning("reCAPTCHA verification failed, %s", err)
    80  					c.Abort()
    81  					break
    82  				}
    83  
    84  				err = reCAPTCHA.Verify(service.CaptchaCode)
    85  				if err != nil {
    86  					util.Log().Warning("reCAPTCHA verification failed, %s", err)
    87  					c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
    88  					c.Abort()
    89  					return
    90  				}
    91  
    92  				break
    93  			case "tcaptcha":
    94  				credential := common.NewCredential(
    95  					options["captcha_TCaptcha_SecretId"],
    96  					options["captcha_TCaptcha_SecretKey"],
    97  				)
    98  				cpf := profile.NewClientProfile()
    99  				cpf.HttpProfile.Endpoint = "captcha.tencentcloudapi.com"
   100  				client, _ := captcha.NewClient(credential, "", cpf)
   101  				request := captcha.NewDescribeCaptchaResultRequest()
   102  				request.CaptchaType = common.Uint64Ptr(9)
   103  				appid, _ := strconv.Atoi(options["captcha_TCaptcha_CaptchaAppId"])
   104  				request.CaptchaAppId = common.Uint64Ptr(uint64(appid))
   105  				request.AppSecretKey = common.StringPtr(options["captcha_TCaptcha_AppSecretKey"])
   106  				request.Ticket = common.StringPtr(service.Ticket)
   107  				request.Randstr = common.StringPtr(service.Randstr)
   108  				request.UserIp = common.StringPtr(c.ClientIP())
   109  				response, err := client.DescribeCaptchaResult(request)
   110  				if err != nil {
   111  					util.Log().Warning("TCaptcha verification failed, %s", err)
   112  					c.Abort()
   113  					break
   114  				}
   115  
   116  				if *response.Response.CaptchaCode != int64(1) {
   117  					c.JSON(200, serializer.Err(serializer.CodeCaptchaRefreshNeeded, captchaRefresh, nil))
   118  					c.Abort()
   119  					return
   120  				}
   121  
   122  				break
   123  			}
   124  		}
   125  		c.Next()
   126  	}
   127  }