From ad92a8e294385303c74d4b806a85c78c59646df0 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Mon, 31 Oct 2022 14:12:27 +0800 Subject: [PATCH 1/9] Allow to enable CAPTCHA validation for login Enable this to require captcha validation for user login. You also must enable `ENABLE_CAPTCHA`. Summary: - refactor template to use captcha.tmpl - add CAPTCHA response string to SignInForm - add CAPTCHA handle and context - add `REQUIRE_CAPTCHA_FOR_LOGIN` config and docs Signed-off-by: Xinyu Zhou --- custom/conf/app.example.ini | 3 ++ .../doc/advanced/config-cheat-sheet.en-us.md | 1 + .../doc/advanced/config-cheat-sheet.zh-cn.md | 3 +- modules/setting/service.go | 2 + routers/web/auth/auth.go | 50 +++++++++++++++++++ services/forms/user_form.go | 4 ++ templates/user/auth/captcha.tmpl | 27 ++++++++++ templates/user/auth/signin_inner.tmpl | 2 + templates/user/auth/signup_inner.tmpl | 28 +---------- .../user/auth/signup_openid_register.tmpl | 28 ++--------- 10 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 templates/user/auth/captcha.tmpl diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index b59ceee4f1db..a1680aedcc33 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -725,6 +725,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 ;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index df1911934c88..7ed5e8ce6ee0 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -594,6 +594,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\] diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index 576007f75b25..f10b6258c87a 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -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`) diff --git a/modules/setting/service.go b/modules/setting/service.go index 10e389995032..d2eb6ebcd7ef 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -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) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 25d70d7c4781..81717109e179 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -170,6 +170,17 @@ func SignIn(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() + if setting.Service.RequireCaptchaForLogin { + 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 + } + ctx.HTML(http.StatusOK, tplSignIn) } @@ -190,12 +201,51 @@ func SignInPost(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() + if setting.Service.RequireCaptchaForLogin { + 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 + } + if ctx.HasError() { ctx.HTML(http.StatusOK, tplSignIn) return } form := web.GetForm(ctx).(*forms.SignInForm) + + if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { + 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"), tplSignIn, &form) + return + } + } + u, source, err := auth_service.UserSignIn(form.UserName, form.Password) if err != nil { if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) { diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 036c2ca3ec2c..90ba5c6449bb 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -160,6 +160,10 @@ type SignInForm struct { // TODO remove required from password for SecondFactorAuthentication Password string `binding:"Required;MaxSize(255)"` Remember bool + // Captcha + GRecaptchaResponse string `form:"g-recaptcha-response"` + HcaptchaResponse string `form:"h-captcha-response"` + McaptchaResponse string `form:"m-captcha-response"` } // Validate validates the fields diff --git a/templates/user/auth/captcha.tmpl b/templates/user/auth/captcha.tmpl new file mode 100644 index 000000000000..70cde7222d64 --- /dev/null +++ b/templates/user/auth/captcha.tmpl @@ -0,0 +1,27 @@ +{{if and .EnableCaptcha (eq .CaptchaType "image")}} +
+ + {{.Captcha.CreateHTML}} +
+
+ + +
+{{end}} +{{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} +
+
+
+{{end}} +{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} +
+
+
+{{end}} +{{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} +
+ {{.locale.Tr "captcha"}} +
+
+
+{{end}} diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 18875f45a391..f14bac10eee7 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -31,6 +31,8 @@ {{end}} + {{template "user/auth/captcha" .}} +
{{end}} - {{if and .EnableCaptcha (eq .CaptchaType "image")}} -
- - {{.Captcha.CreateHTML}} -
-
- - -
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} -
- {{.locale.Tr "captcha"}} -
-
-
- {{end}} + {{template "user/auth/captcha" .}}
diff --git a/templates/user/auth/signup_openid_register.tmpl b/templates/user/auth/signup_openid_register.tmpl index 9c0558311f01..e54600ec8220 100644 --- a/templates/user/auth/signup_openid_register.tmpl +++ b/templates/user/auth/signup_openid_register.tmpl @@ -20,31 +20,9 @@
- {{if and .EnableCaptcha (eq .CaptchaType "image")}} -
- - {{.Captcha.CreateHTML}} -
-
- - -
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} -
-
-
- {{end}} - {{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} -
-
-
- {{end}} + + {{template "user/auth/captcha" .}} +
From f3cef9cd482c79cf5b3dd5424dfa1d4f0b98e455 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Mon, 31 Oct 2022 15:39:11 +0800 Subject: [PATCH 2/9] fix some stupid things Signed-off-by: Xinyu Zhou --- routers/web/auth/auth.go | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 81717109e179..a626b83ba75a 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -170,7 +170,7 @@ func SignIn(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() - if setting.Service.RequireCaptchaForLogin { + if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["Captcha"] = context.GetImageCaptcha() @@ -201,7 +201,14 @@ func SignInPost(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() - if setting.Service.RequireCaptchaForLogin { + if ctx.HasError() { + ctx.HTML(http.StatusOK, tplSignIn) + return + } + + form := web.GetForm(ctx).(*forms.SignInForm) + + if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["Captcha"] = context.GetImageCaptcha() @@ -210,16 +217,7 @@ func SignInPost(ctx *context.Context) { ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL - } - if ctx.HasError() { - ctx.HTML(http.StatusOK, tplSignIn) - return - } - - form := web.GetForm(ctx).(*forms.SignInForm) - - if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { var valid bool var err error switch setting.Service.CaptchaType { From 11dc7ef441a13145af512e847f6d813d616bcc0b Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 31 Oct 2022 22:11:42 +0000 Subject: [PATCH 3/9] as per KN4CK3R Signed-off-by: Andrew Thornton --- templates/user/auth/captcha.tmpl | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/templates/user/auth/captcha.tmpl b/templates/user/auth/captcha.tmpl index 70cde7222d64..6b418c7e2b7f 100644 --- a/templates/user/auth/captcha.tmpl +++ b/templates/user/auth/captcha.tmpl @@ -1,4 +1,4 @@ -{{if and .EnableCaptcha (eq .CaptchaType "image")}} +{{if .EnableCaptcha}}{{if eq .CaptchaType "image"}}
{{.Captcha.CreateHTML}} @@ -7,21 +7,18 @@
-{{end}} -{{if and .EnableCaptcha (eq .CaptchaType "recaptcha")}} +{{else if eq .CaptchaType "recaptcha"}}
-{{end}} -{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}} +{{else if eq .CaptchaType "hcaptcha"}}
-{{end}} -{{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} +{{else if eq .CaptchaType "mcaptcha"}}
{{.locale.Tr "captcha"}}
-{{end}} +{{end}}{{end}} From 3d70bc9f0756c8dd2810769fa330b825cc4e9210 Mon Sep 17 00:00:00 2001 From: Andrew Thornton Date: Mon, 31 Oct 2022 23:13:32 +0000 Subject: [PATCH 4/9] Consolidate CAPTCHA set-up and verification code There is too much copy&paste of this code. Move this to some common functions. Signed-off-by: Andrew Thornton --- modules/context/captcha.go | 58 ++++++++++++++++ routers/web/auth/auth.go | 91 +++---------------------- routers/web/auth/linkaccount.go | 27 +------- routers/web/auth/openid.go | 49 ++----------- services/forms/user_form.go | 15 ++-- services/forms/user_form_auth_openid.go | 7 +- 6 files changed, 79 insertions(+), 168 deletions(-) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index 6117d3071335..2d6de7c2a61b 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -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,55 @@ 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 +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("%s", err.Error()) + } + + if !valid { + ctx.Data["Err_Captcha"] = true + ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, &form) + } +} diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index a626b83ba75a..6faf8c1bf0e0 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -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" @@ -171,14 +168,7 @@ func SignIn(ctx *context.Context) { ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled() if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { - 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.HTML(http.StatusOK, tplSignIn) @@ -209,37 +199,10 @@ func SignInPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.SignInForm) if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { - 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 - - 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()) - } + context.SetCaptchaData(ctx) - if !valid { - ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tplSignIn, &form) + context.VerifyCaptcha(ctx, tplSignIn, form) + if ctx.Written() { return } } @@ -459,14 +422,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 @@ -482,14 +438,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 @@ -503,31 +452,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() { diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 4f3f2062b689..2236eb72872b 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -14,10 +14,7 @@ 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/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" @@ -231,28 +228,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 } } diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 3b1065189d9d..2402d6510d41 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -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/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -369,14 +366,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 { @@ -385,42 +375,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 diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 90ba5c6449bb..4f48462c6ed2 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -90,13 +90,10 @@ func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.E // RegisterForm form for registering type RegisterForm struct { - UserName string `binding:"Required;AlphaDashDot;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;AlphaDashDot;MaxSize(40)"` + Email string `binding:"Required;MaxSize(254)"` + Password string `binding:"MaxSize(255)"` + Retype string } // Validate validates the fields @@ -160,10 +157,6 @@ type SignInForm struct { // TODO remove required from password for SecondFactorAuthentication Password string `binding:"Required;MaxSize(255)"` Remember bool - // Captcha - GRecaptchaResponse string `form:"g-recaptcha-response"` - HcaptchaResponse string `form:"h-captcha-response"` - McaptchaResponse string `form:"m-captcha-response"` } // Validate validates the fields diff --git a/services/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go index 992517f34f0f..8207c14867a8 100644 --- a/services/forms/user_form_auth_openid.go +++ b/services/forms/user_form_auth_openid.go @@ -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;AlphaDashDot;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;AlphaDashDot;MaxSize(40)"` + Email string `binding:"Required;Email;MaxSize(254)"` } // Validate validates the fields From 6ad5f14a67d38d3f6faae1451a7e77ac035a610c Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Tue, 1 Nov 2022 08:23:55 +0800 Subject: [PATCH 5/9] fix type --- modules/context/captcha.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index 2d6de7c2a61b..9033eb7be7f6 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -83,6 +83,6 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form interface{}) { if !valid { ctx.Data["Err_Captcha"] = true - ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, &form) + ctx.RenderWithErr(ctx.Tr("form.captcha_incorrect"), tpl, form) } } From 86a2bd34ef29df6f5a182dcd622202308a51bac9 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Thu, 10 Nov 2022 21:40:35 +0800 Subject: [PATCH 6/9] CAPTCHA response field should be private variables Signed-off-by: Xinyu Zhou --- modules/context/captcha.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index 9033eb7be7f6..48c4438d3b6f 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -51,9 +51,9 @@ func SetCaptchaData(ctx *Context) { } const ( - GRecaptchaResponseField = "g-recaptcha-response" - HcaptchaResponseField = "h-captcha-response" - McaptchaResponseField = "m-captcha-response" + gRecaptchaResponseField = "g-recaptcha-response" + hCaptchaResponseField = "h-captcha-response" + mCaptchaResponseField = "m-captcha-response" ) // VerifyCaptcha verifies Captcha data @@ -68,11 +68,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form interface{}) { case setting.ImageCaptcha: valid = GetImageCaptcha().VerifyReq(ctx.Req) case setting.ReCaptcha: - valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(GRecaptchaResponseField)) + valid, err = recaptcha.Verify(ctx, ctx.Req.Form.Get(gRecaptchaResponseField)) case setting.HCaptcha: - valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(HcaptchaResponseField)) + valid, err = hcaptcha.Verify(ctx, ctx.Req.Form.Get(hCaptchaResponseField)) case setting.MCaptcha: - valid, err = mcaptcha.Verify(ctx, ctx.Req.Form.Get(McaptchaResponseField)) + 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 From 7569531d45f35a6f2534a8869a73c731ed5ec289 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Sat, 12 Nov 2022 08:04:19 +0800 Subject: [PATCH 7/9] Update modules/context/captcha.go Co-authored-by: delvh --- modules/context/captcha.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index 48c4438d3b6f..e891bd02c7ef 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -57,6 +57,7 @@ const ( ) // 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 From 34125aefdd16bf1e85fbcdef40f2afb8f8df3f47 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Sat, 12 Nov 2022 08:23:20 +0800 Subject: [PATCH 8/9] Update modules/context/captcha.go Co-authored-by: delvh --- modules/context/captcha.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/context/captcha.go b/modules/context/captcha.go index e891bd02c7ef..0bd003da6cb3 100644 --- a/modules/context/captcha.go +++ b/modules/context/captcha.go @@ -79,7 +79,7 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form interface{}) { return } if err != nil { - log.Debug("%s", err.Error()) + log.Debug("%v", err) } if !valid { From 1774038afe3e0260083d4e5b27dbd73d946931a8 Mon Sep 17 00:00:00 2001 From: Xinyu Zhou Date: Sat, 12 Nov 2022 09:54:58 +0800 Subject: [PATCH 9/9] Add comment to CAPTCHA filed Signed-off-by: Xinyu Zhou --- templates/user/auth/captcha.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/user/auth/captcha.tmpl b/templates/user/auth/captcha.tmpl index 6b418c7e2b7f..87b22a0720ed 100644 --- a/templates/user/auth/captcha.tmpl +++ b/templates/user/auth/captcha.tmpl @@ -1,6 +1,6 @@ {{if .EnableCaptcha}}{{if eq .CaptchaType "image"}}
- + {{.Captcha.CreateHTML}}