mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Add support mCaptcha as captcha provider (#20458)
https://mcaptcha.org/ Co-authored-by: Felipe Leopoldo Sologuren Gutiérrez <fsologureng@users.noreply.github.com>
This commit is contained in:
		| @@ -698,9 +698,11 @@ ROUTER = console | |||||||
| ;; Enable captcha validation for registration | ;; Enable captcha validation for registration | ||||||
| ;ENABLE_CAPTCHA = false | ;ENABLE_CAPTCHA = false | ||||||
| ;; | ;; | ||||||
| ;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha | ;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha. | ||||||
| ;CAPTCHA_TYPE = image | ;CAPTCHA_TYPE = image | ||||||
| ;; | ;; | ||||||
|  | ;; Change this to use recaptcha.net or other recaptcha service | ||||||
|  | ;RECAPTCHA_URL = https://www.google.com/recaptcha/ | ||||||
| ;; Enable recaptcha to use Google's recaptcha service | ;; Enable recaptcha to use Google's recaptcha service | ||||||
| ;; Go to https://www.google.com/recaptcha/admin to sign up for a key | ;; Go to https://www.google.com/recaptcha/admin to sign up for a key | ||||||
| ;RECAPTCHA_SECRET = | ;RECAPTCHA_SECRET = | ||||||
| @@ -710,8 +712,13 @@ ROUTER = console | |||||||
| ;HCAPTCHA_SECRET = | ;HCAPTCHA_SECRET = | ||||||
| ;HCAPTCHA_SITEKEY = | ;HCAPTCHA_SITEKEY = | ||||||
| ;; | ;; | ||||||
| ;; Change this to use recaptcha.net or other recaptcha service | ;; Change this to use demo.mcaptcha.org or your self-hosted mcaptcha.org instance. | ||||||
| ;RECAPTCHA_URL = https://www.google.com/recaptcha/ | ;MCAPTCHA_URL = https://demo.mcaptcha.org | ||||||
|  | ;; | ||||||
|  | ;; Go to your configured mCaptcha instance and register a sitekey | ||||||
|  | ;; and use your account's secret. | ||||||
|  | ;MCAPTCHA_SECRET = | ||||||
|  | ;MCAPTCHA_SITEKEY = | ||||||
| ;; | ;; | ||||||
| ;; Default value for KeepEmailPrivate | ;; Default value for KeepEmailPrivate | ||||||
| ;; Each new user will get the value of this setting copied into their profile | ;; Each new user will get the value of this setting copied into their profile | ||||||
|   | |||||||
| @@ -579,13 +579,16 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o | |||||||
|    provided email rather than a generated email. |    provided email rather than a generated email. | ||||||
| - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. | - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. | ||||||
| - `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 must `ENABLE_CAPTCHA` also. |    even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`. | ||||||
| - `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha\] | - `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\] | ||||||
| - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. | - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. | ||||||
| - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. | - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. | ||||||
| - `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net. | - `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net. | ||||||
| - `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha. | - `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha. | ||||||
| - `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha. | - `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha. | ||||||
|  | - `MCAPTCHA_SECRET`: **""**: Go to your mCaptcha instance to get a secret for mCaptcha. | ||||||
|  | - `MCAPTCHA_SITEKEY`: **""**: Go to your mCaptcha instance to get a sitekey for mCaptcha. | ||||||
|  | - `MCAPTCHA_URL` **https://demo.mcaptcha.org/**: Set the mCaptcha URL. | ||||||
| - `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private. | - `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private. | ||||||
| - `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default. | - `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default. | ||||||
| - `DEFAULT_USER_IS_RESTRICTED`: **false**: Give new users restricted permissions by default | - `DEFAULT_USER_IS_RESTRICTED`: **false**: Give new users restricted permissions by default | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -5,6 +5,7 @@ go 1.18 | |||||||
| require ( | require ( | ||||||
| 	code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b | 	code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b | ||||||
| 	code.gitea.io/sdk/gitea v0.15.1 | 	code.gitea.io/sdk/gitea v0.15.1 | ||||||
|  | 	codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222 | ||||||
| 	gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb | 	gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb | ||||||
| 	gitea.com/go-chi/cache v0.2.0 | 	gitea.com/go-chi/cache v0.2.0 | ||||||
| 	gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 | 	gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @@ -62,6 +62,8 @@ code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b/go.mod h1:zcNbT/aJE | |||||||
| code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= | code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= | ||||||
| code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= | code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= | ||||||
| code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= | code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= | ||||||
|  | codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222 h1:PCW4i+gnQ9XxF8V+nBch3KWdGe4MiP3xXUCA/z0jhHk= | ||||||
|  | codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM= | ||||||
| contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= | contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= | ||||||
| contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= | contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= | ||||||
| contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= | contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								modules/mcaptcha/mcaptcha.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								modules/mcaptcha/mcaptcha.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | // Copyright 2022 The Gitea Authors. All rights reserved. | ||||||
|  | // Use of this source code is governed by a MIT-style | ||||||
|  | // license that can be found in the LICENSE file. | ||||||
|  |  | ||||||
|  | package mcaptcha | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/setting" | ||||||
|  |  | ||||||
|  | 	"codeberg.org/gusted/mcaptcha" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func Verify(ctx context.Context, token string) (bool, error) { | ||||||
|  | 	valid, err := mcaptcha.Verify(ctx, &mcaptcha.VerifyOpts{ | ||||||
|  | 		InstanceURL: setting.Service.McaptchaURL, | ||||||
|  | 		Sitekey:     setting.Service.McaptchaSitekey, | ||||||
|  | 		Secret:      setting.Service.McaptchaSecret, | ||||||
|  | 		Token:       token, | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return false, fmt.Errorf("wasn't able to verify mCaptcha: %v", err) | ||||||
|  | 	} | ||||||
|  | 	return valid, nil | ||||||
|  | } | ||||||
| @@ -47,6 +47,9 @@ var Service = struct { | |||||||
| 	RecaptchaURL                            string | 	RecaptchaURL                            string | ||||||
| 	HcaptchaSecret                          string | 	HcaptchaSecret                          string | ||||||
| 	HcaptchaSitekey                         string | 	HcaptchaSitekey                         string | ||||||
|  | 	McaptchaSecret                          string | ||||||
|  | 	McaptchaSitekey                         string | ||||||
|  | 	McaptchaURL                             string | ||||||
| 	DefaultKeepEmailPrivate                 bool | 	DefaultKeepEmailPrivate                 bool | ||||||
| 	DefaultAllowCreateOrganization          bool | 	DefaultAllowCreateOrganization          bool | ||||||
| 	DefaultUserIsRestricted                 bool | 	DefaultUserIsRestricted                 bool | ||||||
| @@ -133,6 +136,9 @@ func newService() { | |||||||
| 	Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/") | 	Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/") | ||||||
| 	Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("") | 	Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("") | ||||||
| 	Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("") | 	Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("") | ||||||
|  | 	Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/") | ||||||
|  | 	Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("") | ||||||
|  | 	Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("") | ||||||
| 	Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool() | 	Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool() | ||||||
| 	Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true) | 	Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true) | ||||||
| 	Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false) | 	Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false) | ||||||
|   | |||||||
| @@ -59,6 +59,7 @@ const ( | |||||||
| 	ImageCaptcha = "image" | 	ImageCaptcha = "image" | ||||||
| 	ReCaptcha    = "recaptcha" | 	ReCaptcha    = "recaptcha" | ||||||
| 	HCaptcha     = "hcaptcha" | 	HCaptcha     = "hcaptcha" | ||||||
|  | 	MCaptcha     = "mcaptcha" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // settings | // settings | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										63
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -8,6 +8,7 @@ | |||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@claviska/jquery-minicolors": "2.3.6", |         "@claviska/jquery-minicolors": "2.3.6", | ||||||
|  |         "@mcaptcha/vanilla-glue": "0.1.0-alpha-2", | ||||||
|         "@primer/octicons": "17.4.0", |         "@primer/octicons": "17.4.0", | ||||||
|         "add-asset-webpack-plugin": "2.0.1", |         "add-asset-webpack-plugin": "2.0.1", | ||||||
|         "css-loader": "6.7.1", |         "css-loader": "6.7.1", | ||||||
| @@ -1662,6 +1663,55 @@ | |||||||
|         "jsep": "^0.4.0||^1.0.0" |         "jsep": "^0.4.0||^1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@mcaptcha/core-glue": { | ||||||
|  |       "version": "0.1.0-alpha-3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@mcaptcha/core-glue/-/core-glue-0.1.0-alpha-3.tgz", | ||||||
|  |       "integrity": "sha512-avphBVgf3PPDWuUoDsB2qiXAss2pc00lUILswJaMQofr8FQyflzkhha8H2Z+qGFiX0Iib/yyP2TOtBDbHqE9Tg==", | ||||||
|  |       "funding": [ | ||||||
|  |         { | ||||||
|  |           "type": "individual", | ||||||
|  |           "url": "http://mcaptcha.org/donate" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "liberapay", | ||||||
|  |           "url": "https://liberapay.com/mcaptcha" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "individual", | ||||||
|  |           "url": "http://batsense.net/donate" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "liberapay", | ||||||
|  |           "url": "https://liberapay.com/realaravinth" | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     }, | ||||||
|  |     "node_modules/@mcaptcha/vanilla-glue": { | ||||||
|  |       "version": "0.1.0-alpha-2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@mcaptcha/vanilla-glue/-/vanilla-glue-0.1.0-alpha-2.tgz", | ||||||
|  |       "integrity": "sha512-cQOg3EIhdjk1xoZtjD9SVPwQAnd49FCvHKchwFZZuhdNTeFs7SUHynOCekuGow2Ip0RJZuMZGcRxvWMgd0ogng==", | ||||||
|  |       "funding": [ | ||||||
|  |         { | ||||||
|  |           "type": "individual", | ||||||
|  |           "url": "http://mcaptcha.org/donate" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "liberapay", | ||||||
|  |           "url": "https://liberapay.com/mcaptcha" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "individual", | ||||||
|  |           "url": "http://batsense.net/donate" | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           "type": "liberapay", | ||||||
|  |           "url": "https://liberapay.com/realaravinth" | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       "dependencies": { | ||||||
|  |         "@mcaptcha/core-glue": "^0.1.0-alpha-3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@nodelib/fs.scandir": { |     "node_modules/@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.5", |       "version": "2.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", |       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||||
| @@ -14144,6 +14194,19 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "requires": {} |       "requires": {} | ||||||
|     }, |     }, | ||||||
|  |     "@mcaptcha/core-glue": { | ||||||
|  |       "version": "0.1.0-alpha-3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@mcaptcha/core-glue/-/core-glue-0.1.0-alpha-3.tgz", | ||||||
|  |       "integrity": "sha512-avphBVgf3PPDWuUoDsB2qiXAss2pc00lUILswJaMQofr8FQyflzkhha8H2Z+qGFiX0Iib/yyP2TOtBDbHqE9Tg==" | ||||||
|  |     }, | ||||||
|  |     "@mcaptcha/vanilla-glue": { | ||||||
|  |       "version": "0.1.0-alpha-2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@mcaptcha/vanilla-glue/-/vanilla-glue-0.1.0-alpha-2.tgz", | ||||||
|  |       "integrity": "sha512-cQOg3EIhdjk1xoZtjD9SVPwQAnd49FCvHKchwFZZuhdNTeFs7SUHynOCekuGow2Ip0RJZuMZGcRxvWMgd0ogng==", | ||||||
|  |       "requires": { | ||||||
|  |         "@mcaptcha/core-glue": "^0.1.0-alpha-3" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "@nodelib/fs.scandir": { |     "@nodelib/fs.scandir": { | ||||||
|       "version": "2.1.5", |       "version": "2.1.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", |       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@claviska/jquery-minicolors": "2.3.6", |     "@claviska/jquery-minicolors": "2.3.6", | ||||||
|  |     "@mcaptcha/vanilla-glue": "0.1.0-alpha-2", | ||||||
|     "@primer/octicons": "17.4.0", |     "@primer/octicons": "17.4.0", | ||||||
|     "add-asset-webpack-plugin": "2.0.1", |     "add-asset-webpack-plugin": "2.0.1", | ||||||
|     "css-loader": "6.7.1", |     "css-loader": "6.7.1", | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/eventsource" | 	"code.gitea.io/gitea/modules/eventsource" | ||||||
| 	"code.gitea.io/gitea/modules/hcaptcha" | 	"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/recaptcha" | ||||||
| 	"code.gitea.io/gitea/modules/session" | 	"code.gitea.io/gitea/modules/session" | ||||||
| @@ -414,6 +415,8 @@ func SignUp(ctx *context.Context) { | |||||||
| 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	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 | ||||||
| @@ -435,6 +438,8 @@ func SignUpPost(ctx *context.Context) { | |||||||
| 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	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 | ||||||
| @@ -458,6 +463,8 @@ func SignUpPost(ctx *context.Context) { | |||||||
| 			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) | 			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) | ||||||
| 		case setting.HCaptcha: | 		case setting.HCaptcha: | ||||||
| 			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) | 			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) | ||||||
|  | 		case setting.MCaptcha: | ||||||
|  | 			valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) | ||||||
| 		default: | 		default: | ||||||
| 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | ||||||
| 			return | 			return | ||||||
|   | |||||||
| @@ -16,6 +16,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/hcaptcha" | 	"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/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" | ||||||
| @@ -40,6 +41,8 @@ func LinkAccount(ctx *context.Context) { | |||||||
| 	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL | 	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL | ||||||
| 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | ||||||
| 	ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration | 	ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration | ||||||
| 	ctx.Data["ShowRegistrationButton"] = false | 	ctx.Data["ShowRegistrationButton"] = false | ||||||
| @@ -96,6 +99,8 @@ func LinkAccountPostSignIn(ctx *context.Context) { | |||||||
| 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL | ||||||
| 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | ||||||
| 	ctx.Data["ShowRegistrationButton"] = false | 	ctx.Data["ShowRegistrationButton"] = false | ||||||
|  |  | ||||||
| @@ -195,6 +200,8 @@ func LinkAccountPostRegister(ctx *context.Context) { | |||||||
| 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL | ||||||
| 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | 	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration | ||||||
| 	ctx.Data["ShowRegistrationButton"] = false | 	ctx.Data["ShowRegistrationButton"] = false | ||||||
|  |  | ||||||
| @@ -233,6 +240,8 @@ func LinkAccountPostRegister(ctx *context.Context) { | |||||||
| 			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) | 			valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) | ||||||
| 		case setting.HCaptcha: | 		case setting.HCaptcha: | ||||||
| 			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) | 			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) | ||||||
|  | 		case setting.MCaptcha: | ||||||
|  | 			valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) | ||||||
| 		default: | 		default: | ||||||
| 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | ||||||
| 			return | 			return | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ import ( | |||||||
| 	"code.gitea.io/gitea/modules/context" | 	"code.gitea.io/gitea/modules/context" | ||||||
| 	"code.gitea.io/gitea/modules/hcaptcha" | 	"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/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" | ||||||
| @@ -341,6 +342,8 @@ func RegisterOpenID(ctx *context.Context) { | |||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | ||||||
| 	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL | 	ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL | ||||||
|  | 	ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey | ||||||
|  | 	ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL | ||||||
| 	ctx.Data["OpenID"] = oid | 	ctx.Data["OpenID"] = oid | ||||||
| 	userName, _ := ctx.Session.Get("openid_determined_username").(string) | 	userName, _ := ctx.Session.Get("openid_determined_username").(string) | ||||||
| 	if userName != "" { | 	if userName != "" { | ||||||
| @@ -372,6 +375,8 @@ func RegisterOpenIDPost(ctx *context.Context) { | |||||||
| 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | 	ctx.Data["CaptchaType"] = setting.Service.CaptchaType | ||||||
| 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | 	ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey | ||||||
| 	ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey | 	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 { | ||||||
| @@ -397,6 +402,12 @@ func RegisterOpenIDPost(ctx *context.Context) { | |||||||
| 				return | 				return | ||||||
| 			} | 			} | ||||||
| 			valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) | 			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: | 		default: | ||||||
| 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | 			ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) | ||||||
| 			return | 			return | ||||||
|   | |||||||
| @@ -96,6 +96,7 @@ type RegisterForm struct { | |||||||
| 	Retype             string | 	Retype             string | ||||||
| 	GRecaptchaResponse string `form:"g-recaptcha-response"` | 	GRecaptchaResponse string `form:"g-recaptcha-response"` | ||||||
| 	HcaptchaResponse   string `form:"h-captcha-response"` | 	HcaptchaResponse   string `form:"h-captcha-response"` | ||||||
|  | 	McaptchaResponse   string `form:"m-captcha-response"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Validate validates the fields | // Validate validates the fields | ||||||
|   | |||||||
| @@ -31,6 +31,7 @@ type SignUpOpenIDForm struct { | |||||||
| 	Email              string `binding:"Required;Email;MaxSize(254)"` | 	Email              string `binding:"Required;Email;MaxSize(254)"` | ||||||
| 	GRecaptchaResponse string `form:"g-recaptcha-response"` | 	GRecaptchaResponse string `form:"g-recaptcha-response"` | ||||||
| 	HcaptchaResponse   string `form:"h-captcha-response"` | 	HcaptchaResponse   string `form:"h-captcha-response"` | ||||||
|  | 	McaptchaResponse   string `form:"m-captcha-response"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Validate validates the fields | // Validate validates the fields | ||||||
|   | |||||||
| @@ -54,6 +54,14 @@ | |||||||
| 						<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div> | 						<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div> | ||||||
| 					</div> | 					</div> | ||||||
| 				{{end}} | 				{{end}} | ||||||
|  | 				{{if and .EnableCaptcha (eq .CaptchaType "mcaptcha")}} | ||||||
|  | 					<div class="inline field df ac db-small"> | ||||||
|  | 						<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}} | ||||||
|  |  | ||||||
|  |  | ||||||
| 				<div class="inline field"> | 				<div class="inline field"> | ||||||
| 					<label></label> | 					<label></label> | ||||||
|   | |||||||
| @@ -40,6 +40,11 @@ | |||||||
| 							<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div> | 							<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div> | ||||||
| 						</div> | 						</div> | ||||||
| 					{{end}} | 					{{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> | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								web_src/js/features/mcaptcha.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								web_src/js/features/mcaptcha.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | export async function initMcaptcha() { | ||||||
|  |   const mCaptchaEl = document.querySelector('.m-captcha'); | ||||||
|  |   if (!mCaptchaEl) return; | ||||||
|  |  | ||||||
|  |   const {default: mCaptcha} = await import(/* webpackChunkName: "mcaptcha-vanilla-glue" */'@mcaptcha/vanilla-glue'); | ||||||
|  |   mCaptcha.INPUT_NAME = 'm-captcha-response'; | ||||||
|  |   const siteKey = mCaptchaEl.getAttribute('data-sitekey'); | ||||||
|  |   const instanceURL = mCaptchaEl.getAttribute('data-instance-url'); | ||||||
|  |  | ||||||
|  |   mCaptcha.default({ | ||||||
|  |     siteKey: { | ||||||
|  |       instanceUrl: new URL(instanceURL), | ||||||
|  |       key: siteKey, | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
| @@ -86,6 +86,7 @@ import {initCommonOrganization} from './features/common-organization.js'; | |||||||
| import {initRepoWikiForm} from './features/repo-wiki.js'; | import {initRepoWikiForm} from './features/repo-wiki.js'; | ||||||
| import {initRepoCommentForm, initRepository} from './features/repo-legacy.js'; | import {initRepoCommentForm, initRepository} from './features/repo-legacy.js'; | ||||||
| import {initFormattingReplacements} from './features/formatting.js'; | import {initFormattingReplacements} from './features/formatting.js'; | ||||||
|  | import {initMcaptcha} from './features/mcaptcha.js'; | ||||||
|  |  | ||||||
| // Run time-critical code as soon as possible. This is safe to do because this | // Run time-critical code as soon as possible. This is safe to do because this | ||||||
| // script appears at the end of <body> and rendered HTML is accessible at that point. | // script appears at the end of <body> and rendered HTML is accessible at that point. | ||||||
| @@ -182,6 +183,7 @@ $(document).ready(() => { | |||||||
|   initRepository(); |   initRepository(); | ||||||
|  |  | ||||||
|   initCommitStatuses(); |   initCommitStatuses(); | ||||||
|  |   initMcaptcha(); | ||||||
|  |  | ||||||
|   initUserAuthLinkAccountView(); |   initUserAuthLinkAccountView(); | ||||||
|   initUserAuthOauth2(); |   initUserAuthOauth2(); | ||||||
|   | |||||||
| @@ -156,7 +156,8 @@ textarea:focus, | |||||||
|         padding-left: @create-page-form-input-padding+30px; |         padding-left: @create-page-form-input-padding+30px; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       .inline.field > label { |       .inline.field > label, | ||||||
|  |       .inline.field > span { | ||||||
|         text-align: right; |         text-align: right; | ||||||
|         width: @create-page-form-input-padding; |         width: @create-page-form-input-padding; | ||||||
|         word-wrap: break-word; |         word-wrap: break-word; | ||||||
|   | |||||||
| @@ -168,3 +168,8 @@ | |||||||
| .py-3 { padding-top: .5rem !important; padding-bottom: .5rem !important; } | .py-3 { padding-top: .5rem !important; padding-bottom: .5rem !important; } | ||||||
| .py-4 { padding-top: 1rem !important; padding-bottom: 1rem !important; } | .py-4 { padding-top: 1rem !important; padding-bottom: 1rem !important; } | ||||||
| .py-5 { padding-top: 2rem !important; padding-bottom: 2rem !important; } | .py-5 { padding-top: 2rem !important; padding-bottom: 2rem !important; } | ||||||
|  |  | ||||||
|  | @media @mediaSm { | ||||||
|  |   .db-small { display: block !important; } | ||||||
|  |   .w-100-small { width: 100% !important; } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Gusted
					Gusted