mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 08:30:25 +08: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