Files
zeekayandHanzo Dev aa87442fdd Record upstream authorship centrally in NOTICE instead of in every file header
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the
Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in
NOTICE, alongside LICENSE. The header lint accepts any copyright line above the
SPDX line, so it no longer demands an upstream one.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:50:35 -07:00

88 lines
2.6 KiB
Go

// Copyright 2026 Hanzo AI, Inc. All rights reserved.
// SPDX-License-Identifier: MIT
package context
import (
"fmt"
"image/color"
"sync"
"github.com/hanzoai/git/modules/cache"
"github.com/hanzoai/git/modules/hcaptcha"
"github.com/hanzoai/git/modules/log"
"github.com/hanzoai/git/modules/mcaptcha"
"github.com/hanzoai/git/modules/recaptcha"
"github.com/hanzoai/git/modules/setting"
"github.com/hanzoai/git/modules/templates"
"github.com/hanzoai/git/modules/turnstile"
"github.com/hanzoai/git/modules/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 (
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) {
if !setting.Service.EnableCaptcha {
return
}
var valid bool
var err error
switch setting.Service.CaptchaType {
case setting.ImageCaptcha:
valid = GetImageCaptcha().VerifyReq(ctx.Req)
case setting.ReCaptcha:
valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField))
case setting.HCaptcha:
valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField))
case setting.MCaptcha:
valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(mCaptchaResponseField))
case setting.CfTurnstile:
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
}
if err != nil {
log.Debug("Captcha Verify failed: %v", err)
}
if !valid {
ctx.Data["Err_Captcha"] = true
ctx.RenderWithErrDeprecated(ctx.Tr("form.captcha_incorrect"), tpl, form)
}
}