-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new captcha: cloudflare turnstile #22369
Merged
Merged
Changes from 8 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
a6bfdc5
add new captcha: cloudflare turnstile
ByLCY 8c63433
Change from inline css to using css class
ByLCY 59186ab
Added dark mode for hcaptcha, recaptcha and cloudflare turnstile
ByLCY 0821c09
Use ctx.RemoteAddr() to get the real ip instead of getting it from th…
ByLCY 034dc52
Merge branch 'main' into main
lunny c5d9c49
fix linter errors
ByLCY 4ba29b3
Move code from mcaptcha.js to captcha.js
ByLCY 09b7707
Merge branch 'main' into main
ByLCY a152ec7
Update modules/turnstile/turnstile.go
wolfogre 09ff015
Update modules/turnstile/turnstile.go
wolfogre 0d185a7
Update modules/turnstile/turnstile.go
wolfogre 4b3b828
Modify custom attribute
ByLCY f178ef4
Merge branch 'main' into main
ByLCY 46aa739
Remove the remoteip parameter for Turnstile
ByLCY File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright 2023 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package turnstile | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"net/url" | ||
"strings" | ||
|
||
"code.gitea.io/gitea/modules/json" | ||
"code.gitea.io/gitea/modules/setting" | ||
) | ||
|
||
// Response is the structure of JSON returned from API | ||
type Response struct { | ||
Success bool `json:"success"` | ||
ChallengeTS string `json:"challenge_ts"` | ||
Hostname string `json:"hostname"` | ||
ErrorCodes []ErrorCode `json:"error-codes"` | ||
Action string `json:"login"` | ||
Cdata string `json:"cdata"` | ||
} | ||
|
||
// Verify calls Cloudflare Turnstile API to verify token | ||
func Verify(ctx context.Context, response, ip string) (bool, error) { | ||
// Cloudflare turnstile official access instruction address: https://developers.cloudflare.com/turnstile/get-started/server-side-validation/ | ||
post := url.Values{ | ||
"secret": {setting.Service.CfTurnstileSecret}, | ||
"response": {response}, | ||
"remoteip": {ip}, | ||
} | ||
// Basically a copy of http.PostForm, but with a context | ||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, | ||
"https://challenges.cloudflare.com/turnstile/v0/siteverify", strings.NewReader(post.Encode())) | ||
if err != nil { | ||
return false, fmt.Errorf("Failed to create CAPTCHA request: %w", err) | ||
} | ||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
return false, fmt.Errorf("Failed to send CAPTCHA response: %s", err) | ||
wolfogre marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
defer resp.Body.Close() | ||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return false, fmt.Errorf("Failed to read CAPTCHA response: %s", err) | ||
wolfogre marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
var jsonResponse Response | ||
if err := json.Unmarshal(body, &jsonResponse); err != nil { | ||
return false, fmt.Errorf("Failed to parse CAPTCHA response: %s", err) | ||
wolfogre marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
var respErr error | ||
if len(jsonResponse.ErrorCodes) > 0 { | ||
respErr = jsonResponse.ErrorCodes[0] | ||
} | ||
return jsonResponse.Success, respErr | ||
} | ||
|
||
// ErrorCode is a reCaptcha error | ||
type ErrorCode string | ||
|
||
// String fulfills the Stringer interface | ||
func (e ErrorCode) String() string { | ||
switch e { | ||
case "missing-input-secret": | ||
return "The secret parameter was not passed." | ||
case "invalid-input-secret": | ||
return "The secret parameter was invalid or did not exist." | ||
case "missing-input-response": | ||
return "The response parameter was not passed." | ||
case "invalid-input-response": | ||
return "The response parameter is invalid or has expired." | ||
case "bad-request": | ||
return "The request was rejected because it was malformed." | ||
case "timeout-or-duplicate": | ||
return "The response parameter has already been validated before." | ||
case "internal-error": | ||
return "An internal error happened while validating the response. The request can be retried." | ||
} | ||
return string(e) | ||
} | ||
|
||
// Error fulfills the error interface | ||
func (e ErrorCode) Error() string { | ||
return e.String() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import {isDarkTheme} from '../utils.js'; | ||
|
||
export async function initCaptcha() { | ||
const captchaEl = document.querySelector('#captcha'); | ||
if (!captchaEl) return; | ||
|
||
const siteKey = captchaEl.getAttribute('data-sitekey'); | ||
const isDark = isDarkTheme(); | ||
|
||
const params = { | ||
sitekey: siteKey, | ||
theme: isDark ? 'dark' : 'light' | ||
}; | ||
|
||
switch (captchaEl.getAttribute('captcha-type')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Non-standard attributes usually need the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It was fixed in this commit 4b3b828 |
||
case 'g-recaptcha': { | ||
if (window.grecaptcha) { | ||
window.grecaptcha.ready(() => { | ||
window.grecaptcha.render(captchaEl, params); | ||
}); | ||
} | ||
break; | ||
} | ||
case 'cf-turnstile': { | ||
if (window.turnstile) { | ||
window.turnstile.render(captchaEl, params); | ||
} | ||
break; | ||
} | ||
case 'h-captcha': { | ||
if (window.hcaptcha) { | ||
window.hcaptcha.render(captchaEl, params); | ||
} | ||
break; | ||
} | ||
case 'm-captcha': { | ||
const {default: mCaptcha} = await import(/* webpackChunkName: "mcaptcha-vanilla-glue" */'@mcaptcha/vanilla-glue'); | ||
mCaptcha.INPUT_NAME = 'm-captcha-response'; | ||
const instanceURL = captchaEl.getAttribute('data-instance-url'); | ||
|
||
mCaptcha.default({ | ||
siteKey: { | ||
instanceUrl: new URL(instanceURL), | ||
key: siteKey, | ||
} | ||
}); | ||
break; | ||
} | ||
default: | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
remoteip
is optional. Does Gitea guarantee that the site admin always has the correct reverse-proxy config and Gitea can get the correct user remote IP by RemoteAddr? If no, what would happen? Just a question.Checked with hcaptcha code, hcaptcha also supports
remoteip
but it doesn't use it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My personal opinion is the same as this answer. Therefore, I think it may be a better choice to carry
remoteip
in the parameter.But the usage of
remoteip
above is just my personal guess, cloudflare’s official documentation does not explain how they useremoteip
.If you think that third parties should not be given so much information, then I will remove
remoteip
in a future commit.What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I prefer to keep the same behavior as hcaptcha (no
remoteip
)It might still be fine to have the
remoteip
for the cloudflare turnstile, then it could be better to have enough comments.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'm going to remove
remoteip
. If there is enough information in the future to prove that it would be better to carry this parameter, then we will discuss whether to add it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was removed in this commit 46aa739