mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09: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 = 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. | ||||
| ;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 | ||||
|    provided full name for the user. | ||||
| - `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 | ||||
|    even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`. | ||||
| - `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\] | ||||
|   | ||||
| @@ -145,7 +145,8 @@ menu: | ||||
| - `ENABLE_NOTIFY_MAIL`: 是否发送工单创建等提醒邮件,需要 `Mailer` 被激活。 | ||||
| - `ENABLE_REVERSE_PROXY_AUTHENTICATION`: 允许反向代理认证,更多细节见:https://github.com/gogits/gogs/issues/165 | ||||
| - `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: 允许通过反向认证做自动注册。 | ||||
| - `ENABLE_CAPTCHA`: 注册时使用图片验证码。 | ||||
| - `ENABLE_CAPTCHA`: **false**: 注册时使用图片验证码。 | ||||
| - `REQUIRE_CAPTCHA_FOR_LOGIN`: **false**: 登录时需要图片验证码。需要同时开启 `ENABLE_CAPTCHA`。 | ||||
|  | ||||
| ### Service - Expore (`service.explore`) | ||||
|  | ||||
|   | ||||
| @@ -5,9 +5,15 @@ | ||||
| package context | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"sync" | ||||
|  | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"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" | ||||
|  | ||||
| 	"gitea.com/go-chi/captcha" | ||||
| @@ -28,3 +34,56 @@ func GetImageCaptcha() *captcha.Captcha { | ||||
| 	}) | ||||
| 	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 | ||||
| 	EnableReverseProxyFullName              bool | ||||
| 	EnableCaptcha                           bool | ||||
| 	RequireCaptchaForLogin                  bool | ||||
| 	RequireExternalRegistrationCaptcha      bool | ||||
| 	RequireExternalRegistrationPassword     bool | ||||
| 	CaptchaType                             string | ||||
| @@ -130,6 +131,7 @@ func newService() { | ||||
| 	Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() | ||||
| 	Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() | ||||
| 	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.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool() | ||||
| 	Service.CaptchaType = sec.Key("CAPTCHA_TYPE").MustString(ImageCaptcha) | ||||
|   | ||||
| @@ -17,11 +17,8 @@ import ( | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"code.gitea.io/gitea/modules/context" | ||||
| 	"code.gitea.io/gitea/modules/eventsource" | ||||
| 	"code.gitea.io/gitea/modules/hcaptcha" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/mcaptcha" | ||||
| 	"code.gitea.io/gitea/modules/password" | ||||
| 	"code.gitea.io/gitea/modules/recaptcha" | ||||
| 	"code.gitea.io/gitea/modules/session" | ||||
| 	"code.gitea.io/gitea/modules/setting" | ||||
| 	"code.gitea.io/gitea/modules/timeutil" | ||||
| @@ -163,6 +160,10 @@ func SignIn(ctx *context.Context) { | ||||
| 	ctx.Data["PageIsLogin"] = true | ||||
| 	ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() | ||||
|  | ||||
| 	if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { | ||||
| 		context.SetCaptchaData(ctx) | ||||
| 	} | ||||
|  | ||||
| 	ctx.HTML(http.StatusOK, tplSignIn) | ||||
| } | ||||
|  | ||||
| @@ -189,6 +190,16 @@ func SignInPost(ctx *context.Context) { | ||||
| 	} | ||||
|  | ||||
| 	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) | ||||
| 	if err != nil { | ||||
| 		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["EnableCaptcha"] = setting.Service.EnableCaptcha | ||||
| 	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 | ||||
| 	context.SetCaptchaData(ctx) | ||||
| 	ctx.Data["PageIsSignUp"] = 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["EnableCaptcha"] = setting.Service.EnableCaptcha | ||||
| 	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 | ||||
| 	context.SetCaptchaData(ctx) | ||||
| 	ctx.Data["PageIsSignUp"] = true | ||||
|  | ||||
| 	// Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true | ||||
| @@ -427,31 +424,9 @@ func SignUpPost(ctx *context.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if setting.Service.EnableCaptcha { | ||||
| 		var valid bool | ||||
| 		var err error | ||||
| 		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 | ||||
| 		} | ||||
| 	context.VerifyCaptcha(ctx, tplSignUp, form) | ||||
| 	if ctx.Written() { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if !form.IsEmailDomainAllowed() { | ||||
|   | ||||
| @@ -14,10 +14,6 @@ import ( | ||||
| 	user_model "code.gitea.io/gitea/models/user" | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"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/web" | ||||
| 	auth_service "code.gitea.io/gitea/services/auth" | ||||
| @@ -221,28 +217,8 @@ func LinkAccountPostRegister(ctx *context.Context) { | ||||
| 	} | ||||
|  | ||||
| 	if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha { | ||||
| 		var valid bool | ||||
| 		var err error | ||||
| 		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) | ||||
| 		context.VerifyCaptcha(ctx, tplLinkAccount, form) | ||||
| 		if ctx.Written() { | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -13,10 +13,7 @@ import ( | ||||
| 	"code.gitea.io/gitea/modules/auth/openid" | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"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/util" | ||||
| 	"code.gitea.io/gitea/modules/web" | ||||
| @@ -357,14 +354,7 @@ func RegisterOpenIDPost(ctx *context.Context) { | ||||
| 	ctx.Data["PageIsSignIn"] = true | ||||
| 	ctx.Data["PageIsOpenIDRegister"] = true | ||||
| 	ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp | ||||
| 	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha | ||||
| 	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 | ||||
| 	context.SetCaptchaData(ctx) | ||||
| 	ctx.Data["OpenID"] = oid | ||||
|  | ||||
| 	if setting.Service.AllowOnlyInternalRegistration { | ||||
| @@ -373,42 +363,11 @@ func RegisterOpenIDPost(ctx *context.Context) { | ||||
| 	} | ||||
|  | ||||
| 	if setting.Service.EnableCaptcha { | ||||
| 		var valid bool | ||||
| 		var err error | ||||
| 		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) | ||||
| 		if err := ctx.Req.ParseForm(); err != nil { | ||||
| 			ctx.ServerError("", err) | ||||
| 			return | ||||
| 		} | ||||
| 		context.VerifyCaptcha(ctx, tplSignUpOID, form) | ||||
| 	} | ||||
|  | ||||
| 	length := setting.MinPasswordLength | ||||
|   | ||||
| @@ -91,13 +91,10 @@ func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.E | ||||
|  | ||||
| // RegisterForm form for registering | ||||
| type RegisterForm struct { | ||||
| 	UserName           string `binding:"Required;Username;MaxSize(40)"` | ||||
| 	Email              string `binding:"Required;MaxSize(254)"` | ||||
| 	Password           string `binding:"MaxSize(255)"` | ||||
| 	Retype             string | ||||
| 	GRecaptchaResponse string `form:"g-recaptcha-response"` | ||||
| 	HcaptchaResponse   string `form:"h-captcha-response"` | ||||
| 	McaptchaResponse   string `form:"m-captcha-response"` | ||||
| 	UserName string `binding:"Required;Username;MaxSize(40)"` | ||||
| 	Email    string `binding:"Required;MaxSize(254)"` | ||||
| 	Password string `binding:"MaxSize(255)"` | ||||
| 	Retype   string | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| type SignUpOpenIDForm struct { | ||||
| 	UserName           string `binding:"Required;Username;MaxSize(40)"` | ||||
| 	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"` | ||||
| 	UserName string `binding:"Required;Username;MaxSize(40)"` | ||||
| 	Email    string `binding:"Required;Email;MaxSize(254)"` | ||||
| } | ||||
|  | ||||
| // 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> | ||||
| 			{{end}} | ||||
|  | ||||
| 			{{template "user/auth/captcha" .}} | ||||
|  | ||||
| 			<div class="inline field"> | ||||
| 				<label></label> | ||||
| 				<button class="ui green button"> | ||||
|   | ||||
| @@ -34,34 +34,8 @@ | ||||
| 						<input id="retype" name="retype" type="password" value="{{.retype}}" autocomplete="new-password" required> | ||||
| 					</div> | ||||
| 				{{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"> | ||||
| 					<label></label> | ||||
|   | ||||
| @@ -20,31 +20,9 @@ | ||||
| 						<label for="email">{{.locale.Tr "email"}}</label> | ||||
| 						<input id="email" name="email" type="email" value="{{.email}}" required> | ||||
| 					</div> | ||||
| 					{{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 required"> | ||||
| 							<div class="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div> | ||||
| 						</div> | ||||
| 					{{end}} | ||||
|  | ||||
| 					{{template "user/auth/captcha" .}} | ||||
|  | ||||
| 					<div class="inline field"> | ||||
| 						<label for="openid">OpenID URI</label> | ||||
| 						<input id="openid" value="{{.OpenID}}" readonly> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user