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 }