mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-03 13:04:08 +02:00
refactor: move go-chi/captcha into Gitea (#39529)
The `gitea.com/go-chi/captcha` package only exists for Gitea, so it moves into `modules/imagecaptcha`. - Reloading an expired challenge shows a new image instead of a broken one - Every answer is consumed on its first check - OpenID registration stops after a failed captcha --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
1 parent
e6ffbea888
commit
873efed5a6
17 files changed
+656
-59
No files matched your search
+10
-36
@@ -5,65 +5,37 @@ package context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"sync"
|
||||
|
||||
"gitea.dev/modules/cache"
|
||||
"gitea.dev/modules/hcaptcha"
|
||||
"gitea.dev/modules/imagecaptcha"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/mcaptcha"
|
||||
"gitea.dev/modules/recaptcha"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/templates"
|
||||
"gitea.dev/modules/turnstile"
|
||||
|
||||
"gitea.com/go-chi/captcha"
|
||||
)
|
||||
|
||||
var (
|
||||
imageCaptchaOnce sync.Once
|
||||
cpt *captcha.Captcha
|
||||
)
|
||||
|
||||
// GetImageCaptcha returns global image captcha
|
||||
func GetImageCaptcha() *captcha.Captcha {
|
||||
imageCaptchaOnce.Do(func() {
|
||||
cpt = captcha.NewCaptcha(captcha.Options{
|
||||
SubURL: setting.AppSubURL,
|
||||
// Use a color palette with high contrast colors suitable for both light and dark modes
|
||||
// These colors provide good visibility and readability in both themes
|
||||
ColorPalette: color.Palette{
|
||||
color.RGBA{R: 234, G: 67, B: 53, A: 255}, // Bright red
|
||||
color.RGBA{R: 66, G: 133, B: 244, A: 255}, // Medium blue
|
||||
color.RGBA{R: 52, G: 168, B: 83, A: 255}, // Green
|
||||
color.RGBA{R: 251, G: 188, B: 5, A: 255}, // Yellow/gold
|
||||
color.RGBA{R: 171, G: 71, B: 188, A: 255}, // Purple
|
||||
},
|
||||
})
|
||||
cpt.Store = cache.GetCache().ChiCache()
|
||||
})
|
||||
return cpt
|
||||
}
|
||||
|
||||
const (
|
||||
imageCaptchaIDField = "captcha_id"
|
||||
imageCaptchaAnswerField = "captcha"
|
||||
gRecaptchaResponseField = "g-recaptcha-response"
|
||||
hCaptchaResponseField = "h-captcha-response"
|
||||
mCaptchaResponseField = "mcaptcha__token" // this form key is hard-coded in the mcaptcha frontend library
|
||||
cfTurnstileResponseField = "cf-turnstile-response"
|
||||
)
|
||||
|
||||
// VerifyCaptcha verifies Captcha data
|
||||
// No-op if captchas are not enabled
|
||||
func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) {
|
||||
// VerifyCaptcha returns whether the captcha is solved or disabled, otherwise it renders tpl with an error
|
||||
func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) bool {
|
||||
if !setting.Service.EnableCaptcha {
|
||||
return
|
||||
return true
|
||||
}
|
||||
|
||||
var valid bool
|
||||
var err error
|
||||
switch setting.Service.CaptchaType {
|
||||
case setting.ImageCaptcha:
|
||||
valid = GetImageCaptcha().VerifyReq(ctx.Req)
|
||||
valid = imagecaptcha.Verify(ctx.FormString(imageCaptchaIDField), ctx.FormString(imageCaptchaAnswerField))
|
||||
case setting.ReCaptcha:
|
||||
valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField))
|
||||
case setting.HCaptcha:
|
||||
@@ -74,7 +46,7 @@ func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) {
|
||||
valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField))
|
||||
default:
|
||||
ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType))
|
||||
return
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug("Captcha Verify failed: %v", err)
|
||||
@@ -83,5 +55,7 @@ func VerifyCaptcha(ctx *Context, tpl templates.TplName, form any) {
|
||||
if !valid {
|
||||
ctx.Data["Err_Captcha"] = true
|
||||
ctx.RenderWithErrDeprecated(ctx.Tr("form.captcha_incorrect"), tpl, form)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in new issue
Block a user