From 41c0776568b3fa1bf825439103085146260e16a8 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Wed, 27 Jan 2021 22:56:54 +0800
Subject: [PATCH] Fix captcha (#14488)

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Lauris BH <lauris@nix.lv>
---
 modules/cache/cache.go                        | 20 +---------
 modules/context/captcha.go                    |  2 +
 modules/context/context.go                    | 38 ++++++-------------
 modules/setting/cache.go                      |  4 ++
 routers/routes/web.go                         |  4 +-
 routers/user/auth.go                          |  5 +++
 routers/user/auth_openid.go                   |  2 +
 templates/user/auth/signup_inner.tmpl         |  2 +-
 .../user/auth/signup_openid_register.tmpl     |  2 +-
 9 files changed, 30 insertions(+), 49 deletions(-)

diff --git a/modules/cache/cache.go b/modules/cache/cache.go
index 3f8885ee30..609f5a242b 100644
--- a/modules/cache/cache.go
+++ b/modules/cache/cache.go
@@ -27,24 +27,6 @@ func newCache(cacheConfig setting.Cache) (mc.Cache, error) {
 	})
 }
 
-// Cache is the interface that operates the cache data.
-type Cache interface {
-	// Put puts value into cache with key and expire time.
-	Put(key string, val interface{}, timeout int64) error
-	// Get gets cached value by given key.
-	Get(key string) interface{}
-	// Delete deletes cached value by given key.
-	Delete(key string) error
-	// Incr increases cached int-type value by given key as a counter.
-	Incr(key string) error
-	// Decr decreases cached int-type value by given key as a counter.
-	Decr(key string) error
-	// IsExist returns true if cached value exists.
-	IsExist(key string) bool
-	// Flush deletes all cached data.
-	Flush() error
-}
-
 // NewContext start cache service
 func NewContext() error {
 	var err error
@@ -59,7 +41,7 @@ func NewContext() error {
 }
 
 // GetCache returns the currently configured cache
-func GetCache() Cache {
+func GetCache() mc.Cache {
 	return conn
 }
 
diff --git a/modules/context/captcha.go b/modules/context/captcha.go
index 956380ed73..b8540136a1 100644
--- a/modules/context/captcha.go
+++ b/modules/context/captcha.go
@@ -7,6 +7,7 @@ package context
 import (
 	"sync"
 
+	"code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/setting"
 
 	"gitea.com/go-chi/captcha"
@@ -21,6 +22,7 @@ func GetImageCaptcha() *captcha.Captcha {
 		cpt = captcha.NewCaptcha(captcha.Options{
 			SubURL: setting.AppSubURL,
 		})
+		cpt.Store = cache.GetCache()
 	})
 	return cpt
 }
diff --git a/modules/context/context.go b/modules/context/context.go
index 630129b8c1..e5025205c9 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -23,6 +23,7 @@ import (
 	"code.gitea.io/gitea/models"
 	"code.gitea.io/gitea/modules/auth/sso"
 	"code.gitea.io/gitea/modules/base"
+	mc "code.gitea.io/gitea/modules/cache"
 	"code.gitea.io/gitea/modules/log"
 	"code.gitea.io/gitea/modules/middlewares"
 	"code.gitea.io/gitea/modules/setting"
@@ -499,23 +500,8 @@ func getCsrfOpts() CsrfOptions {
 
 // Contexter initializes a classic context for a request.
 func Contexter() func(next http.Handler) http.Handler {
-	rnd := templates.HTMLRenderer()
-
-	var c cache.Cache
-	var err error
-	if setting.CacheService.Enabled {
-		c, err = cache.NewCacher(cache.Options{
-			Adapter:       setting.CacheService.Adapter,
-			AdapterConfig: setting.CacheService.Conn,
-			Interval:      setting.CacheService.Interval,
-		})
-		if err != nil {
-			panic(err)
-		}
-	}
-
+	var rnd = templates.HTMLRenderer()
 	var csrfOpts = getCsrfOpts()
-	//var flashEncryptionKey, _ = NewSecret()
 
 	return func(next http.Handler) http.Handler {
 		return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
@@ -524,7 +510,7 @@ func Contexter() func(next http.Handler) http.Handler {
 			var link = setting.AppSubURL + strings.TrimSuffix(req.URL.EscapedPath(), "/")
 			var ctx = Context{
 				Resp:    NewResponse(resp),
-				Cache:   c,
+				Cache:   mc.GetCache(),
 				Locale:  locale,
 				Link:    link,
 				Render:  rnd,
@@ -571,16 +557,14 @@ func Contexter() func(next http.Handler) http.Handler {
 			}
 			ctx.Resp.Before(func(resp ResponseWriter) {
 				if flash := f.Encode(); len(flash) > 0 {
-					if err == nil {
-						middlewares.SetCookie(resp, "macaron_flash", flash, 0,
-							setting.SessionConfig.CookiePath,
-							middlewares.Domain(setting.SessionConfig.Domain),
-							middlewares.HTTPOnly(true),
-							middlewares.Secure(setting.SessionConfig.Secure),
-							//middlewares.SameSite(opt.SameSite), FIXME: we need a samesite config
-						)
-						return
-					}
+					middlewares.SetCookie(resp, "macaron_flash", flash, 0,
+						setting.SessionConfig.CookiePath,
+						middlewares.Domain(setting.SessionConfig.Domain),
+						middlewares.HTTPOnly(true),
+						middlewares.Secure(setting.SessionConfig.Secure),
+						//middlewares.SameSite(opt.SameSite), FIXME: we need a samesite config
+					)
+					return
 				}
 
 				ctx.SetCookie("macaron_flash", "", -1,
diff --git a/modules/setting/cache.go b/modules/setting/cache.go
index af47bd085a..618be2482a 100644
--- a/modules/setting/cache.go
+++ b/modules/setting/cache.go
@@ -68,6 +68,10 @@ func newCacheService() {
 
 	if CacheService.Enabled {
 		log.Info("Cache Service Enabled")
+	} else {
+		log.Warn("Cache Service Disabled so that captcha disabled too")
+		// captcha depends on cache service
+		Service.EnableCaptcha = false
 	}
 
 	sec = Cfg.Section("cache.last_commit")
diff --git a/routers/routes/web.go b/routers/routes/web.go
index 6b6322f048..cbd7c0b7ca 100644
--- a/routers/routes/web.go
+++ b/routers/routes/web.go
@@ -161,7 +161,9 @@ func WebRoutes() *web.Route {
 
 	mailer.InitMailRender(templates.Mailer())
 
-	r.Use(captcha.Captchaer(context.GetImageCaptcha()))
+	if setting.Service.EnableCaptcha {
+		r.Use(captcha.Captchaer(context.GetImageCaptcha()))
+	}
 	// Removed: toolbox.Toolboxer middleware will provide debug informations which seems unnecessary
 	r.Use(context.Contexter())
 	// Removed: SetAutoHead allow a get request redirect to head if get method is not exist
diff --git a/routers/user/auth.go b/routers/user/auth.go
index 909d0a2ee5..bb877767ae 100644
--- a/routers/user/auth.go
+++ b/routers/user/auth.go
@@ -747,6 +747,7 @@ func LinkAccount(ctx *context.Context) {
 	ctx.Data["Title"] = ctx.Tr("link_account")
 	ctx.Data["LinkAccountMode"] = true
 	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
+	ctx.Data["Captcha"] = context.GetImageCaptcha()
 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
@@ -800,6 +801,7 @@ func LinkAccountPostSignIn(ctx *context.Context) {
 	ctx.Data["LinkAccountModeSignIn"] = true
 	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
 	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["DisableRegistration"] = setting.Service.DisableRegistration
@@ -885,6 +887,7 @@ func LinkAccountPostRegister(ctx *context.Context) {
 	ctx.Data["LinkAccountModeRegister"] = true
 	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
 	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["DisableRegistration"] = setting.Service.DisableRegistration
@@ -1063,6 +1066,7 @@ func SignUp(ctx *context.Context) {
 
 	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
@@ -1083,6 +1087,7 @@ func SignUpPost(ctx *context.Context) {
 
 	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
diff --git a/routers/user/auth_openid.go b/routers/user/auth_openid.go
index 1efcc7eda8..3f5c9f7248 100644
--- a/routers/user/auth_openid.go
+++ b/routers/user/auth_openid.go
@@ -329,6 +329,7 @@ func RegisterOpenID(ctx *context.Context) {
 	ctx.Data["PageIsOpenIDRegister"] = true
 	ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp
 	ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
+	ctx.Data["Captcha"] = context.GetImageCaptcha()
 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType
 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
@@ -360,6 +361,7 @@ func RegisterOpenIDPost(ctx *context.Context) {
 	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
diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl
index 70fc2947c3..4e8c0adb4f 100644
--- a/templates/user/auth/signup_inner.tmpl
+++ b/templates/user/auth/signup_inner.tmpl
@@ -37,7 +37,7 @@
 				{{if and .EnableCaptcha (eq .CaptchaType "image")}}
 					<div class="inline field">
 						<label></label>
-						{{.Captcha.CreateHtml}}
+						{{.Captcha.CreateHTML}}
 					</div>
 					<div class="required inline field {{if .Err_Captcha}}error{{end}}">
 						<label for="captcha">{{.i18n.Tr "captcha"}}</label>
diff --git a/templates/user/auth/signup_openid_register.tmpl b/templates/user/auth/signup_openid_register.tmpl
index 3138cfe13b..90af77476b 100644
--- a/templates/user/auth/signup_openid_register.tmpl
+++ b/templates/user/auth/signup_openid_register.tmpl
@@ -23,7 +23,7 @@
 					{{if and .EnableCaptcha (eq .CaptchaType "image")}}
 						<div class="inline field">
 							<label></label>
-							{{.Captcha.CreateHtml}}
+							{{.Captcha.CreateHTML}}
 						</div>
 						<div class="required inline field {{if .Err_Captcha}}error{{end}}">
 							<label for="captcha">{{.i18n.Tr "captcha"}}</label>