mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Add option to enable CAPTCHA validation for login (#21638)
Enable this to require captcha validation for user login. You also must enable `ENABLE_CAPTCHA`. Summary: - Consolidate CAPTCHA template - add CAPTCHA handle and context - add `REQUIRE_CAPTCHA_FOR_LOGIN` config and docs - Consolidate CAPTCHA set-up and verification code Partially resolved #6049 Signed-off-by: Xinyu Zhou <i@sourcehut.net> Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		@@ -759,6 +759,9 @@ ROUTER = console
 | 
				
			|||||||
;; Enable captcha validation for registration
 | 
					;; Enable captcha validation for registration
 | 
				
			||||||
;ENABLE_CAPTCHA = false
 | 
					;ENABLE_CAPTCHA = false
 | 
				
			||||||
;;
 | 
					;;
 | 
				
			||||||
 | 
					;; Enable this to require captcha validation for login
 | 
				
			||||||
 | 
					;REQUIRE_CAPTCHA_FOR_LOGIN = false
 | 
				
			||||||
 | 
					;;
 | 
				
			||||||
;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha.
 | 
					;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha.
 | 
				
			||||||
;CAPTCHA_TYPE = image
 | 
					;CAPTCHA_TYPE = image
 | 
				
			||||||
;;
 | 
					;;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -634,6 +634,7 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o
 | 
				
			|||||||
- `ENABLE_REVERSE_PROXY_FULL_NAME`: **false**: Enable this to allow to auto-registration with a
 | 
					- `ENABLE_REVERSE_PROXY_FULL_NAME`: **false**: Enable this to allow to auto-registration with a
 | 
				
			||||||
   provided full name for the user.
 | 
					   provided full name for the user.
 | 
				
			||||||
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
 | 
					- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
 | 
				
			||||||
 | 
					- `REQUIRE_CAPTCHA_FOR_LOGIN`: **false**: Enable this to require captcha validation for login. You also must enable `ENABLE_CAPTCHA`.
 | 
				
			||||||
- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
 | 
					- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
 | 
				
			||||||
   even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`.
 | 
					   even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`.
 | 
				
			||||||
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\]
 | 
					- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -145,7 +145,8 @@ menu:
 | 
				
			|||||||
- `ENABLE_NOTIFY_MAIL`: 是否发送工单创建等提醒邮件,需要 `Mailer` 被激活。
 | 
					- `ENABLE_NOTIFY_MAIL`: 是否发送工单创建等提醒邮件,需要 `Mailer` 被激活。
 | 
				
			||||||
- `ENABLE_REVERSE_PROXY_AUTHENTICATION`: 允许反向代理认证,更多细节见:https://github.com/gogits/gogs/issues/165
 | 
					- `ENABLE_REVERSE_PROXY_AUTHENTICATION`: 允许反向代理认证,更多细节见:https://github.com/gogits/gogs/issues/165
 | 
				
			||||||
- `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: 允许通过反向认证做自动注册。
 | 
					- `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: 允许通过反向认证做自动注册。
 | 
				
			||||||
- `ENABLE_CAPTCHA`: 注册时使用图片验证码。
 | 
					- `ENABLE_CAPTCHA`: **false**: 注册时使用图片验证码。
 | 
				
			||||||
 | 
					- `REQUIRE_CAPTCHA_FOR_LOGIN`: **false**: 登录时需要图片验证码。需要同时开启 `ENABLE_CAPTCHA`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Service - Expore (`service.explore`)
 | 
					### Service - Expore (`service.explore`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,9 +5,15 @@
 | 
				
			|||||||
package context
 | 
					package context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/cache"
 | 
						"code.gitea.io/gitea/modules/cache"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/hcaptcha"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/mcaptcha"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/recaptcha"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gitea.com/go-chi/captcha"
 | 
						"gitea.com/go-chi/captcha"
 | 
				
			||||||
@@ -28,3 +34,56 @@ func GetImageCaptcha() *captcha.Captcha {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
	return cpt
 | 
						return cpt
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetCaptchaData sets common captcha data
 | 
				
			||||||
 | 
					func SetCaptchaData(ctx *Context) {
 | 
				
			||||||
 | 
						if !setting.Service.EnableCaptcha {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
 | 
				
			||||||
 | 
						ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
 | 
				
			||||||
 | 
						ctx.Data["Captcha"] = GetImageCaptcha()
 | 
				
			||||||
 | 
						ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 | 
				
			||||||
 | 
						ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
 | 
				
			||||||
 | 
						ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
 | 
				
			||||||
 | 
						ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
 | 
				
			||||||
 | 
						ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						gRecaptchaResponseField = "g-recaptcha-response"
 | 
				
			||||||
 | 
						hCaptchaResponseField   = "h-captcha-response"
 | 
				
			||||||
 | 
						mCaptchaResponseField   = "m-captcha-response"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// VerifyCaptcha verifies Captcha data
 | 
				
			||||||
 | 
					// No-op if captchas are not enabled
 | 
				
			||||||
 | 
					func VerifyCaptcha(ctx *Context, tpl base.TplName, form interface{}) {
 | 
				
			||||||
 | 
						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))
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Debug("%v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !valid {
 | 
				
			||||||
 | 
							ctx.Data["Err_Captcha"] = true
 | 
				
			||||||
 | 
							ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, form)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,6 +40,7 @@ var Service = struct {
 | 
				
			|||||||
	EnableReverseProxyEmail                 bool
 | 
						EnableReverseProxyEmail                 bool
 | 
				
			||||||
	EnableReverseProxyFullName              bool
 | 
						EnableReverseProxyFullName              bool
 | 
				
			||||||
	EnableCaptcha                           bool
 | 
						EnableCaptcha                           bool
 | 
				
			||||||
 | 
						RequireCaptchaForLogin                  bool
 | 
				
			||||||
	RequireExternalRegistrationCaptcha      bool
 | 
						RequireExternalRegistrationCaptcha      bool
 | 
				
			||||||
	RequireExternalRegistrationPassword     bool
 | 
						RequireExternalRegistrationPassword     bool
 | 
				
			||||||
	CaptchaType                             string
 | 
						CaptchaType                             string
 | 
				
			||||||
@@ -130,6 +131,7 @@ func newService() {
 | 
				
			|||||||
	Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool()
 | 
						Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool()
 | 
				
			||||||
	Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool()
 | 
						Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool()
 | 
				
			||||||
	Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false)
 | 
						Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false)
 | 
				
			||||||
 | 
						Service.RequireCaptchaForLogin = sec.Key("REQUIRE_CAPTCHA_FOR_LOGIN").MustBool(false)
 | 
				
			||||||
	Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha)
 | 
						Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha)
 | 
				
			||||||
	Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool()
 | 
						Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool()
 | 
				
			||||||
	Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha)
 | 
						Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,11 +17,8 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/eventsource"
 | 
						"code.gitea.io/gitea/modules/eventsource"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/hcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/mcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/password"
 | 
						"code.gitea.io/gitea/modules/password"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/recaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/session"
 | 
						"code.gitea.io/gitea/modules/session"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
						"code.gitea.io/gitea/modules/timeutil"
 | 
				
			||||||
@@ -163,6 +160,10 @@ func SignIn(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["PageIsLogin"] = true
 | 
						ctx.Data["PageIsLogin"] = true
 | 
				
			||||||
	ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled()
 | 
						ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
 | 
				
			||||||
 | 
							context.SetCaptchaData(ctx)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplSignIn)
 | 
						ctx.HTML(http.StatusOK, tplSignIn)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -189,6 +190,16 @@ func SignInPost(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	form := web.GetForm(ctx).(*forms.SignInForm)
 | 
						form := web.GetForm(ctx).(*forms.SignInForm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
 | 
				
			||||||
 | 
							context.SetCaptchaData(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							context.VerifyCaptcha(ctx, tplSignIn, form)
 | 
				
			||||||
 | 
							if ctx.Written() {
 | 
				
			||||||
 | 
								return
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
 | 
						u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
 | 
							if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
 | 
				
			||||||
@@ -383,14 +394,7 @@ func SignUp(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
 | 
						ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
 | 
						context.SetCaptchaData(ctx)
 | 
				
			||||||
	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["Captcha"] = context.GetImageCaptcha()
 | 
					 | 
				
			||||||
	ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 | 
					 | 
				
			||||||
	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["PageIsSignUp"] = true
 | 
						ctx.Data["PageIsSignUp"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
						// Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
				
			||||||
@@ -406,14 +410,7 @@ func SignUpPost(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
 | 
						ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/sign_up"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
 | 
						context.SetCaptchaData(ctx)
 | 
				
			||||||
	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["Captcha"] = context.GetImageCaptcha()
 | 
					 | 
				
			||||||
	ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 | 
					 | 
				
			||||||
	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["PageIsSignUp"] = true
 | 
						ctx.Data["PageIsSignUp"] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
						// Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
				
			||||||
@@ -427,31 +424,9 @@ func SignUpPost(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.EnableCaptcha {
 | 
						context.VerifyCaptcha(ctx, tplSignUp, form)
 | 
				
			||||||
		var valid bool
 | 
						if ctx.Written() {
 | 
				
			||||||
		var err error
 | 
							return
 | 
				
			||||||
		switch setting.Service.CaptchaType {
 | 
					 | 
				
			||||||
		case setting.ImageCaptcha:
 | 
					 | 
				
			||||||
			valid = context.GetImageCaptcha().VerifyReq(ctx.Req)
 | 
					 | 
				
			||||||
		case setting.ReCaptcha:
 | 
					 | 
				
			||||||
			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.HCaptcha:
 | 
					 | 
				
			||||||
			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.MCaptcha:
 | 
					 | 
				
			||||||
			valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse)
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Debug("%s", err.Error())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if !valid {
 | 
					 | 
				
			||||||
			ctx.Data["Err_Captcha"] = true
 | 
					 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUp, &form)
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !form.IsEmailDomainAllowed() {
 | 
						if !form.IsEmailDomainAllowed() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,10 +14,6 @@ import (
 | 
				
			|||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/hcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/mcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/recaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web"
 | 
						"code.gitea.io/gitea/modules/web"
 | 
				
			||||||
	auth_service "code.gitea.io/gitea/services/auth"
 | 
						auth_service "code.gitea.io/gitea/services/auth"
 | 
				
			||||||
@@ -221,28 +217,8 @@ func LinkAccountPostRegister(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha {
 | 
						if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha {
 | 
				
			||||||
		var valid bool
 | 
							context.VerifyCaptcha(ctx, tplLinkAccount, form)
 | 
				
			||||||
		var err error
 | 
							if ctx.Written() {
 | 
				
			||||||
		switch setting.Service.CaptchaType {
 | 
					 | 
				
			||||||
		case setting.ImageCaptcha:
 | 
					 | 
				
			||||||
			valid = context.GetImageCaptcha().VerifyReq(ctx.Req)
 | 
					 | 
				
			||||||
		case setting.ReCaptcha:
 | 
					 | 
				
			||||||
			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.HCaptcha:
 | 
					 | 
				
			||||||
			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.MCaptcha:
 | 
					 | 
				
			||||||
			valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse)
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Debug("%s", err.Error())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if !valid {
 | 
					 | 
				
			||||||
			ctx.Data["Err_Captcha"] = true
 | 
					 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplLinkAccount, &form)
 | 
					 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,10 +13,7 @@ import (
 | 
				
			|||||||
	"code.gitea.io/gitea/modules/auth/openid"
 | 
						"code.gitea.io/gitea/modules/auth/openid"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/base"
 | 
						"code.gitea.io/gitea/modules/base"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/context"
 | 
						"code.gitea.io/gitea/modules/context"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/hcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/mcaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/recaptcha"
 | 
					 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/util"
 | 
						"code.gitea.io/gitea/modules/util"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/web"
 | 
						"code.gitea.io/gitea/modules/web"
 | 
				
			||||||
@@ -357,14 +354,7 @@ func RegisterOpenIDPost(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["PageIsSignIn"] = true
 | 
						ctx.Data["PageIsSignIn"] = true
 | 
				
			||||||
	ctx.Data["PageIsOpenIDRegister"] = true
 | 
						ctx.Data["PageIsOpenIDRegister"] = true
 | 
				
			||||||
	ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp
 | 
						ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp
 | 
				
			||||||
	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
 | 
						context.SetCaptchaData(ctx)
 | 
				
			||||||
	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["Captcha"] = context.GetImageCaptcha()
 | 
					 | 
				
			||||||
	ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 | 
					 | 
				
			||||||
	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
 | 
					 | 
				
			||||||
	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
 | 
					 | 
				
			||||||
	ctx.Data["OpenID"] = oid
 | 
						ctx.Data["OpenID"] = oid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.AllowOnlyInternalRegistration {
 | 
						if setting.Service.AllowOnlyInternalRegistration {
 | 
				
			||||||
@@ -373,42 +363,11 @@ func RegisterOpenIDPost(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.EnableCaptcha {
 | 
						if setting.Service.EnableCaptcha {
 | 
				
			||||||
		var valid bool
 | 
							if err := ctx.Req.ParseForm(); err != nil {
 | 
				
			||||||
		var err error
 | 
								ctx.ServerError("", err)
 | 
				
			||||||
		switch setting.Service.CaptchaType {
 | 
					 | 
				
			||||||
		case setting.ImageCaptcha:
 | 
					 | 
				
			||||||
			valid = context.GetImageCaptcha().VerifyReq(ctx.Req)
 | 
					 | 
				
			||||||
		case setting.ReCaptcha:
 | 
					 | 
				
			||||||
			if err := ctx.Req.ParseForm(); err != nil {
 | 
					 | 
				
			||||||
				ctx.ServerError("", err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.HCaptcha:
 | 
					 | 
				
			||||||
			if err := ctx.Req.ParseForm(); err != nil {
 | 
					 | 
				
			||||||
				ctx.ServerError("", err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse)
 | 
					 | 
				
			||||||
		case setting.MCaptcha:
 | 
					 | 
				
			||||||
			if err := ctx.Req.ParseForm(); err != nil {
 | 
					 | 
				
			||||||
				ctx.ServerError("", err)
 | 
					 | 
				
			||||||
				return
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse)
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
 | 
					 | 
				
			||||||
			return
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			log.Debug("%s", err.Error())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if !valid {
 | 
					 | 
				
			||||||
			ctx.Data["Err_Captcha"] = true
 | 
					 | 
				
			||||||
			ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignUpOID, &form)
 | 
					 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							context.VerifyCaptcha(ctx, tplSignUpOID, form)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	length := setting.MinPasswordLength
 | 
						length := setting.MinPasswordLength
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -91,13 +91,10 @@ func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.E
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// RegisterForm form for registering
 | 
					// RegisterForm form for registering
 | 
				
			||||||
type RegisterForm struct {
 | 
					type RegisterForm struct {
 | 
				
			||||||
	UserName           string `binding:"Required;Username;MaxSize(40)"`
 | 
						UserName string `binding:"Required;Username;MaxSize(40)"`
 | 
				
			||||||
	Email              string `binding:"Required;MaxSize(254)"`
 | 
						Email    string `binding:"Required;MaxSize(254)"`
 | 
				
			||||||
	Password           string `binding:"MaxSize(255)"`
 | 
						Password string `binding:"MaxSize(255)"`
 | 
				
			||||||
	Retype             string
 | 
						Retype   string
 | 
				
			||||||
	GRecaptchaResponse string `form:"g-recaptcha-response"`
 | 
					 | 
				
			||||||
	HcaptchaResponse   string `form:"h-captcha-response"`
 | 
					 | 
				
			||||||
	McaptchaResponse   string `form:"m-captcha-response"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Validate validates the fields
 | 
					// Validate validates the fields
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,11 +27,8 @@ func (f *SignInOpenIDForm) Validate(req *http.Request, errs binding.Errors) bind
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// SignUpOpenIDForm form for signin up with OpenID
 | 
					// SignUpOpenIDForm form for signin up with OpenID
 | 
				
			||||||
type SignUpOpenIDForm struct {
 | 
					type SignUpOpenIDForm struct {
 | 
				
			||||||
	UserName           string `binding:"Required;Username;MaxSize(40)"`
 | 
						UserName string `binding:"Required;Username;MaxSize(40)"`
 | 
				
			||||||
	Email              string `binding:"Required;Email;MaxSize(254)"`
 | 
						Email    string `binding:"Required;Email;MaxSize(254)"`
 | 
				
			||||||
	GRecaptchaResponse string `form:"g-recaptcha-response"`
 | 
					 | 
				
			||||||
	HcaptchaResponse   string `form:"h-captcha-response"`
 | 
					 | 
				
			||||||
	McaptchaResponse   string `form:"m-captcha-response"`
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Validate validates the fields
 | 
					// Validate validates the fields
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								templates/user/auth/captcha.tmpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								templates/user/auth/captcha.tmpl
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					{{if .EnableCaptcha}}{{if eq .CaptchaType "image"}}
 | 
				
			||||||
 | 
						<div class="inline field">
 | 
				
			||||||
 | 
							<label>{{/* This is CAPTCHA field */}}</label>
 | 
				
			||||||
 | 
							{{.Captcha.CreateHTML}}
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
						<div class="required inline field {{if .Err_Captcha}}error{{end}}">
 | 
				
			||||||
 | 
							<label for="captcha">{{.locale.Tr "captcha"}}</label>
 | 
				
			||||||
 | 
							<input id="captcha" name="captcha" value="{{.captcha}}" autocomplete="off">
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					{{else if eq .CaptchaType "recaptcha"}}
 | 
				
			||||||
 | 
						<div class="inline field required">
 | 
				
			||||||
 | 
							<div class="g-recaptcha" data-sitekey="{{.RecaptchaSitekey}}"></div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					{{else if eq .CaptchaType "hcaptcha"}}
 | 
				
			||||||
 | 
						<div class="inline field required">
 | 
				
			||||||
 | 
							<div class="h-captcha" data-sitekey="{{.HcaptchaSitekey}}"></div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					{{else if eq .CaptchaType "mcaptcha"}}
 | 
				
			||||||
 | 
						<div class="inline field df ac db-small captcha-field">
 | 
				
			||||||
 | 
							<span>{{.locale.Tr "captcha"}}</span>
 | 
				
			||||||
 | 
							<div class="border-secondary w-100-small" id="mcaptcha__widget-container" style="width: 50%; height: 5em"></div>
 | 
				
			||||||
 | 
							<div class="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
 | 
					{{end}}{{end}}
 | 
				
			||||||
@@ -31,6 +31,8 @@
 | 
				
			|||||||
			</div>
 | 
								</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								{{template "user/auth/captcha" .}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			<div class="inline field">
 | 
								<div class="inline field">
 | 
				
			||||||
				<label></label>
 | 
									<label></label>
 | 
				
			||||||
				<button class="ui green button">
 | 
									<button class="ui green button">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,34 +34,8 @@
 | 
				
			|||||||
						<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required>
 | 
											<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
				{{end}}
 | 
									{{end}}
 | 
				
			||||||
				{{if and .EnableCaptcha (eq .CaptchaType "image")}}
 | 
					 | 
				
			||||||
					<div class="inline field">
 | 
					 | 
				
			||||||
						<label></label>
 | 
					 | 
				
			||||||
						{{.Captcha.CreateHTML}}
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
					<div class="required inline field {{if .Err_Captcha}}error{{end}}">
 | 
					 | 
				
			||||||
						<label for="captcha">{{.locale.Tr "captcha"}}</label>
 | 
					 | 
				
			||||||
						<input id="captcha" name="captcha" value="{{.captcha}}" autocomplete="off">
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				{{end}}
 | 
					 | 
				
			||||||
				{{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}}
 | 
					 | 
				
			||||||
					<div class="inline field required">
 | 
					 | 
				
			||||||
						<div class="g-recaptcha" data-sitekey="{{.RecaptchaSitekey}}"></div>
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				{{end}}
 | 
					 | 
				
			||||||
				{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}}
 | 
					 | 
				
			||||||
					<div class="inline field required">
 | 
					 | 
				
			||||||
						<div class="h-captcha" data-sitekey="{{.HcaptchaSitekey}}"></div>
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				{{end}}
 | 
					 | 
				
			||||||
				{{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}}
 | 
					 | 
				
			||||||
					<div class="inline field df ac db-small captcha-field">
 | 
					 | 
				
			||||||
						<span>{{.locale.Tr "captcha"}}</span>
 | 
					 | 
				
			||||||
						<div class="border-secondary w-100-small" id="mcaptcha__widget-container" style="width: 50%; height: 5em"></div>
 | 
					 | 
				
			||||||
						<div class="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div>
 | 
					 | 
				
			||||||
					</div>
 | 
					 | 
				
			||||||
				{{end}}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									{{template "user/auth/captcha" .}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				<div class="inline field">
 | 
									<div class="inline field">
 | 
				
			||||||
					<label></label>
 | 
										<label></label>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,31 +20,9 @@
 | 
				
			|||||||
						<label for="email">{{.locale.Tr "email"}}</label>
 | 
											<label for="email">{{.locale.Tr "email"}}</label>
 | 
				
			||||||
						<input id="email" name="email" type="email" value="{{.email}}" required>
 | 
											<input id="email" name="email" type="email" value="{{.email}}" required>
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
					{{if and .EnableCaptcha (eq .CaptchaType "image")}}
 | 
					
 | 
				
			||||||
						<div class="inline field">
 | 
										{{template "user/auth/captcha" .}}
 | 
				
			||||||
							<label></label>
 | 
					
 | 
				
			||||||
							{{.Captcha.CreateHTML}}
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
						<div class="required inline field {{if .Err_Captcha}}error{{end}}">
 | 
					 | 
				
			||||||
							<label for="captcha">{{.locale.Tr "captcha"}}</label>
 | 
					 | 
				
			||||||
							<input id="captcha" name="captcha" value="{{.captcha}}" autocomplete="off">
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
					{{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}}
 | 
					 | 
				
			||||||
						<div class="inline field required">
 | 
					 | 
				
			||||||
							<div class="g-recaptcha" data-sitekey="{{.RecaptchaSitekey}}"></div>
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
					{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}}
 | 
					 | 
				
			||||||
						<div class="inline field required">
 | 
					 | 
				
			||||||
							<div class="h-captcha" data-sitekey="{{.HcaptchaSitekey}}"></div>
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
					{{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}}
 | 
					 | 
				
			||||||
						<div class="inline field required">
 | 
					 | 
				
			||||||
							<div class="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div>
 | 
					 | 
				
			||||||
						</div>
 | 
					 | 
				
			||||||
					{{end}}
 | 
					 | 
				
			||||||
					<div class="inline field">
 | 
										<div class="inline field">
 | 
				
			||||||
						<label for="openid">OpenID URI</label>
 | 
											<label for="openid">OpenID URI</label>
 | 
				
			||||||
						<input id="openid" value="{{.OpenID}}" readonly>
 | 
											<input id="openid" value="{{.OpenID}}" readonly>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user