Skip to content

Commit 72636fd

Browse files
jolheiserzeripath
andauthored
hCaptcha Support (#12594)
* Initial work on hCaptcha Signed-off-by: jolheiser <[email protected]> * Use module Signed-off-by: jolheiser <[email protected]> * Format Signed-off-by: jolheiser <[email protected]> * At least return and debug log a captcha error Signed-off-by: jolheiser <[email protected]> * Pass context to hCaptcha Signed-off-by: jolheiser <[email protected]> * Add context to recaptcha Signed-off-by: jolheiser <[email protected]> * fix lint Signed-off-by: Andrew Thornton <[email protected]> * Finish hcaptcha Signed-off-by: jolheiser <[email protected]> * Update example config Signed-off-by: jolheiser <[email protected]> * Apply error fix for recaptcha Signed-off-by: jolheiser <[email protected]> * Change recaptcha ChallengeTS to string Signed-off-by: jolheiser <[email protected]> Co-authored-by: Andrew Thornton <[email protected]>
1 parent 5460bf8 commit 72636fd

File tree

25 files changed

+344
-20
lines changed

25 files changed

+344
-20
lines changed

custom/conf/app.example.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,12 +585,15 @@ ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
585585
ENABLE_REVERSE_PROXY_EMAIL = false
586586
; Enable captcha validation for registration
587587
ENABLE_CAPTCHA = false
588-
; Type of captcha you want to use. Options: image, recaptcha
588+
; Type of captcha you want to use. Options: image, recaptcha, hcaptcha
589589
CAPTCHA_TYPE = image
590590
; Enable recaptcha to use Google's recaptcha service
591591
; Go to https://www.google.com/recaptcha/admin to sign up for a key
592592
RECAPTCHA_SECRET =
593593
RECAPTCHA_SITEKEY =
594+
; For hCaptcha, create an account at https://accounts.hcaptcha.com/login to get your keys
595+
HCAPTCHA_SECRET =
596+
HCAPTCHA_SITEKEY =
594597
; Change this to use recaptcha.net or other recaptcha service
595598
RECAPTCHA_URL = https://www.google.com/recaptcha/
596599
; Default value for KeepEmailPrivate

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,10 +429,12 @@ relation to port exhaustion.
429429
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
430430
- `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation
431431
even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also.
432-
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
432+
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha\]
433433
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
434434
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
435435
- `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net.
436+
- `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha.
437+
- `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha.
436438
- `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private.
437439
- `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default.
438440
- `DEFAULT_ENABLE_DEPENDENCIES`: **true**: Enable this to have dependencies enabled by default.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ require (
101101
github.com/yuin/goldmark v1.2.1
102102
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
103103
github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60
104+
go.jolheiser.com/hcaptcha v0.0.4
104105
go.jolheiser.com/pwn v0.0.3
105106
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
106107
golang.org/x/net v0.0.0-20200904194848-62affa334b73

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,8 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK
933933
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
934934
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
935935
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
936+
go.jolheiser.com/hcaptcha v0.0.4 h1:RrDERcr/Tz/kWyJenjVtI+V09RtLinXxlAemiwN5F+I=
937+
go.jolheiser.com/hcaptcha v0.0.4/go.mod h1:aw32WQOxnQZ6E06C0LypCf+sxNxPACyOnq+ZGnrIYho=
936938
go.jolheiser.com/pwn v0.0.3 h1:MQowb3QvCL5r5NmHmCPxw93SdjfgJ0q6rAwYn4i1Hjg=
937939
go.jolheiser.com/pwn v0.0.3/go.mod h1:/j5Dl8ftNqqJ8Dlx3YTrJV1wIR2lWOTyrNU3Qe7rk6I=
938940
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
@@ -1085,7 +1087,6 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
10851087
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10861088
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10871089
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1088-
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo=
10891090
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10901091
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff h1:1CPUrky56AcgSpxz/KfgzQWzfG09u5YOL8MvPYBlrL8=
10911092
golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1136,7 +1137,6 @@ golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8T
11361137
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
11371138
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
11381139
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1139-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
11401140
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
11411141
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
11421142
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

modules/auth/user_form.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ type RegisterForm struct {
8383
Password string `binding:"MaxSize(255)"`
8484
Retype string
8585
GRecaptchaResponse string `form:"g-recaptcha-response"`
86+
HcaptchaResponse string `form:"h-captcha-response"`
8687
}
8788

8889
// Validate validates the fields

modules/auth/user_form_auth_openid.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type SignUpOpenIDForm struct {
2525
UserName string `binding:"Required;AlphaDashDot;MaxSize(40)"`
2626
Email string `binding:"Required;Email;MaxSize(254)"`
2727
GRecaptchaResponse string `form:"g-recaptcha-response"`
28+
HcaptchaResponse string `form:"h-captcha-response"`
2829
}
2930

3031
// Validate validates the fields

modules/hcaptcha/hcaptcha.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2020 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package hcaptcha
6+
7+
import (
8+
"context"
9+
10+
"code.gitea.io/gitea/modules/setting"
11+
12+
"go.jolheiser.com/hcaptcha"
13+
)
14+
15+
// Verify calls hCaptcha API to verify token
16+
func Verify(ctx context.Context, response string) (bool, error) {
17+
client, err := hcaptcha.New(setting.Service.HcaptchaSecret, hcaptcha.WithContext(ctx))
18+
if err != nil {
19+
return false, err
20+
}
21+
22+
resp, err := client.Verify(response, hcaptcha.PostOptions{
23+
Sitekey: setting.Service.HcaptchaSitekey,
24+
})
25+
if err != nil {
26+
return false, err
27+
}
28+
29+
var respErr error
30+
if len(resp.ErrorCodes) > 0 {
31+
respErr = resp.ErrorCodes[0]
32+
}
33+
return resp.Success, respErr
34+
}

modules/recaptcha/recaptcha.go

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,43 @@
55
package recaptcha
66

77
import (
8+
"context"
89
"encoding/json"
910
"fmt"
1011
"io/ioutil"
1112
"net/http"
1213
"net/url"
13-
"time"
14+
"strings"
1415

1516
"code.gitea.io/gitea/modules/setting"
1617
"code.gitea.io/gitea/modules/util"
1718
)
1819

1920
// Response is the structure of JSON returned from API
2021
type Response struct {
21-
Success bool `json:"success"`
22-
ChallengeTS time.Time `json:"challenge_ts"`
23-
Hostname string `json:"hostname"`
24-
ErrorCodes []string `json:"error-codes"`
22+
Success bool `json:"success"`
23+
ChallengeTS string `json:"challenge_ts"`
24+
Hostname string `json:"hostname"`
25+
ErrorCodes []ErrorCode `json:"error-codes"`
2526
}
2627

2728
const apiURL = "api/siteverify"
2829

2930
// Verify calls Google Recaptcha API to verify token
30-
func Verify(response string) (bool, error) {
31-
resp, err := http.PostForm(util.URLJoin(setting.Service.RecaptchaURL, apiURL),
32-
url.Values{"secret": {setting.Service.RecaptchaSecret}, "response": {response}})
31+
func Verify(ctx context.Context, response string) (bool, error) {
32+
post := url.Values{
33+
"secret": {setting.Service.RecaptchaSecret},
34+
"response": {response},
35+
}
36+
// Basically a copy of http.PostForm, but with a context
37+
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
38+
util.URLJoin(setting.Service.RecaptchaURL, apiURL), strings.NewReader(post.Encode()))
39+
if err != nil {
40+
return false, fmt.Errorf("Failed to create CAPTCHA request: %v", err)
41+
}
42+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
43+
44+
resp, err := http.DefaultClient.Do(req)
3345
if err != nil {
3446
return false, fmt.Errorf("Failed to send CAPTCHA response: %s", err)
3547
}
@@ -43,6 +55,36 @@ func Verify(response string) (bool, error) {
4355
if err != nil {
4456
return false, fmt.Errorf("Failed to parse CAPTCHA response: %s", err)
4557
}
58+
var respErr error
59+
if len(jsonResponse.ErrorCodes) > 0 {
60+
respErr = jsonResponse.ErrorCodes[0]
61+
}
62+
return jsonResponse.Success, respErr
63+
}
64+
65+
// ErrorCode is a reCaptcha error
66+
type ErrorCode string
67+
68+
// String fulfills the Stringer interface
69+
func (e ErrorCode) String() string {
70+
switch e {
71+
case "missing-input-secret":
72+
return "The secret parameter is missing."
73+
case "invalid-input-secret":
74+
return "The secret parameter is invalid or malformed."
75+
case "missing-input-response":
76+
return "The response parameter is missing."
77+
case "invalid-input-response":
78+
return "The response parameter is invalid or malformed."
79+
case "bad-request":
80+
return "The request is invalid or malformed."
81+
case "timeout-or-duplicate":
82+
return "The response is no longer valid: either is too old or has been used previously."
83+
}
84+
return string(e)
85+
}
4686

47-
return jsonResponse.Success, nil
87+
// Error fulfills the error interface
88+
func (e ErrorCode) Error() string {
89+
return e.String()
4890
}

modules/setting/service.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ var Service struct {
3535
RecaptchaSecret string
3636
RecaptchaSitekey string
3737
RecaptchaURL string
38+
HcaptchaSecret string
39+
HcaptchaSitekey string
3840
DefaultKeepEmailPrivate bool
3941
DefaultAllowCreateOrganization bool
4042
EnableTimetracking bool
@@ -76,6 +78,8 @@ func newService() {
7678
Service.RecaptchaSecret = sec.Key("RECAPTCHA_SECRET").MustString("")
7779
Service.RecaptchaSitekey = sec.Key("RECAPTCHA_SITEKEY").MustString("")
7880
Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/")
81+
Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("")
82+
Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("")
7983
Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool()
8084
Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true)
8185
Service.EnableTimetracking = sec.Key("ENABLE_TIMETRACKING").MustBool(true)

modules/setting/setting.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const (
5959
const (
6060
ImageCaptcha = "image"
6161
ReCaptcha = "recaptcha"
62+
HCaptcha = "hcaptcha"
6263
)
6364

6465
// settings

routers/user/auth.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"code.gitea.io/gitea/modules/base"
1818
"code.gitea.io/gitea/modules/context"
1919
"code.gitea.io/gitea/modules/eventsource"
20+
"code.gitea.io/gitea/modules/hcaptcha"
2021
"code.gitea.io/gitea/modules/log"
2122
"code.gitea.io/gitea/modules/password"
2223
"code.gitea.io/gitea/modules/recaptcha"
@@ -896,15 +897,21 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
896897

897898
if setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha {
898899
var valid bool
900+
var err error
899901
switch setting.Service.CaptchaType {
900902
case setting.ImageCaptcha:
901903
valid = cpt.VerifyReq(ctx.Req)
902904
case setting.ReCaptcha:
903-
valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
905+
valid, err = recaptcha.Verify(ctx.Req.Context(), form.GRecaptchaResponse)
906+
case setting.HCaptcha:
907+
valid, err = hcaptcha.Verify(ctx.Req.Context(), form.HcaptchaResponse)
904908
default:
905909
ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
906910
return
907911
}
912+
if err != nil {
913+
log.Debug("%s", err.Error())
914+
}
908915

909916
if !valid {
910917
ctx.Data["Err_Captcha"] = true
@@ -1040,6 +1047,7 @@ func SignUp(ctx *context.Context) {
10401047
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
10411048
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
10421049
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
1050+
ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
10431051
ctx.Data["PageIsSignUp"] = true
10441052

10451053
//Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
@@ -1058,6 +1066,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
10581066
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
10591067
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
10601068
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
1069+
ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
10611070
ctx.Data["PageIsSignUp"] = true
10621071

10631072
//Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
@@ -1073,15 +1082,21 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
10731082

10741083
if setting.Service.EnableCaptcha {
10751084
var valid bool
1085+
var err error
10761086
switch setting.Service.CaptchaType {
10771087
case setting.ImageCaptcha:
10781088
valid = cpt.VerifyReq(ctx.Req)
10791089
case setting.ReCaptcha:
1080-
valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
1090+
valid, err = recaptcha.Verify(ctx.Req.Context(), form.GRecaptchaResponse)
1091+
case setting.HCaptcha:
1092+
valid, err = hcaptcha.Verify(ctx.Req.Context(), form.HcaptchaResponse)
10811093
default:
10821094
ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
10831095
return
10841096
}
1097+
if err != nil {
1098+
log.Debug("%s", err.Error())
1099+
}
10851100

10861101
if !valid {
10871102
ctx.Data["Err_Captcha"] = true

routers/user/auth_openid.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"code.gitea.io/gitea/modules/base"
1515
"code.gitea.io/gitea/modules/context"
1616
"code.gitea.io/gitea/modules/generate"
17+
"code.gitea.io/gitea/modules/hcaptcha"
1718
"code.gitea.io/gitea/modules/log"
1819
"code.gitea.io/gitea/modules/recaptcha"
1920
"code.gitea.io/gitea/modules/setting"
@@ -330,6 +331,7 @@ func RegisterOpenID(ctx *context.Context) {
330331
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha
331332
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
332333
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
334+
ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
333335
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
334336
ctx.Data["OpenID"] = oid
335337
userName, _ := ctx.Session.Get("openid_determined_username").(string)
@@ -359,24 +361,34 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si
359361
ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL
360362
ctx.Data["CaptchaType"] = setting.Service.CaptchaType
361363
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
364+
ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
362365
ctx.Data["OpenID"] = oid
363366

364367
if setting.Service.EnableCaptcha {
365368
var valid bool
369+
var err error
366370
switch setting.Service.CaptchaType {
367371
case setting.ImageCaptcha:
368372
valid = cpt.VerifyReq(ctx.Req)
369373
case setting.ReCaptcha:
370-
err := ctx.Req.ParseForm()
371-
if err != nil {
374+
if err := ctx.Req.ParseForm(); err != nil {
372375
ctx.ServerError("", err)
373376
return
374377
}
375-
valid, _ = recaptcha.Verify(form.GRecaptchaResponse)
378+
valid, err = recaptcha.Verify(ctx.Req.Context(), form.GRecaptchaResponse)
379+
case setting.HCaptcha:
380+
if err := ctx.Req.ParseForm(); err != nil {
381+
ctx.ServerError("", err)
382+
return
383+
}
384+
valid, err = hcaptcha.Verify(ctx.Req.Context(), form.HcaptchaResponse)
376385
default:
377386
ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType))
378387
return
379388
}
389+
if err != nil {
390+
log.Debug("%s", err.Error())
391+
}
380392

381393
if !valid {
382394
ctx.Data["Err_Captcha"] = true

templates/base/footer.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
{{if eq .CaptchaType "recaptcha"}}
2929
<script src='{{ URLJoin .RecaptchaURL "api.js"}}' async></script>
3030
{{end}}
31+
{{if eq .CaptchaType "hcaptcha"}}
32+
<script src='https://hcaptcha.com/1/api.js' async></script>
33+
{{end}}
3134
{{end}}
3235
<script src="{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}"></script>
3336
{{template "custom/footer" .}}

templates/user/auth/signup_inner.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
<div class="g-recaptcha" data-sitekey="{{ .RecaptchaSitekey }}"></div>
5252
</div>
5353
{{end}}
54+
{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}}
55+
<div class="inline field required">
56+
<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div>
57+
</div>
58+
{{end}}
5459

5560
<div class="inline field">
5661
<label></label>

templates/user/auth/signup_openid_register.tmpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
<div class="g-recaptcha" data-sitekey="{{ .RecaptchaSitekey }}"></div>
3636
</div>
3737
{{end}}
38+
{{if and .EnableCaptcha (eq .CaptchaType "hcaptcha")}}
39+
<div class="inline field required">
40+
<div class="h-captcha" data-sitekey="{{ .HcaptchaSitekey }}"></div>
41+
</div>
42+
{{end}}
3843
<div class="inline field">
3944
<label for="openid">OpenID URI</label>
4045
<input id="openid" value="{{ .OpenID }}" readonly>

vendor/go.jolheiser.com/hcaptcha/.gitignore

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)