Add Cap Captcha support (#2511)

* Add Cap Captcha support

- Add CaptchaCap type constant in types.go
- Add Cap struct with InstanceURL, KeyID, and KeySecret fields
- Add CapCaptcha method in provider.go to return Cap settings
- Add default settings for Cap captcha in setting.go
- Implement Cap captcha verification logic in middleware
- Expose Cap captcha settings in site API

This adds support for Cap captcha service as an alternative
captcha option alongside existing reCAPTCHA, Turnstile and
built-in captcha options.

* update cap json tags
This commit is contained in:
WittF
2025-06-19 11:31:17 +08:00
committed by GitHub
parent 9a216cd09e
commit 9f9796f2f3
5 changed files with 83 additions and 0 deletions

View File

@@ -38,6 +38,9 @@ type (
turnstileResponse struct {
Success bool `json:"success"`
}
capResponse struct {
Success bool `json:"success"`
}
)
// CaptchaRequired 验证请求签名
@@ -127,6 +130,61 @@ func CaptchaRequired(enabled func(c *gin.Context) bool) gin.HandlerFunc {
return
}
break
case setting.CaptchaCap:
captchaSetting := settings.CapCaptcha(c)
if captchaSetting.InstanceURL == "" || captchaSetting.KeyID == "" || captchaSetting.KeySecret == "" {
l.Warning("Cap verification failed: missing configuration")
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeCaptchaError, "Captcha configuration error", nil))
c.Abort()
return
}
r := dep.RequestClient(
request2.WithContext(c),
request2.WithLogger(logging.FromContext(c)),
request2.WithHeader(http.Header{"Content-Type": []string{"application/json"}}),
)
capEndpoint := strings.TrimSuffix(captchaSetting.InstanceURL, "/") + "/" + captchaSetting.KeyID + "/siteverify"
requestBody := map[string]string{
"secret": captchaSetting.KeySecret,
"response": service.Ticket,
}
requestData, err := json.Marshal(requestBody)
if err != nil {
l.Warning("Cap verification failed: %s", err)
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeCaptchaError, "Captcha validation failed", err))
c.Abort()
return
}
res, err := r.Request("POST", capEndpoint, strings.NewReader(string(requestData))).
CheckHTTPResponse(http.StatusOK).
GetResponse()
if err != nil {
l.Warning("Cap verification failed: %s", err)
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeCaptchaError, "Captcha validation failed", err))
c.Abort()
return
}
var capRes capResponse
err = json.Unmarshal([]byte(res), &capRes)
if err != nil {
l.Warning("Cap verification failed: %s", err)
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeCaptchaError, "Captcha validation failed", err))
c.Abort()
return
}
if !capRes.Success {
l.Warning("Cap verification failed: validation returned false")
c.JSON(200, serializer.ErrWithDetails(c, serializer.CodeCaptchaError, "Captcha validation failed", nil))
c.Abort()
return
}
break
}
}