Files
MokoGitea/modules/recaptcha/recaptcha.go
T
Jonathan Miller 9a5720e8ad
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
PR RC Release / Build RC Release (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
chore: rename Go module from git. to code.mokoconsulting.tech (#336)
Full namespace migration: update the Go module path and all import
statements from git.mokoconsulting.tech to code.mokoconsulting.tech.
Also updates all URL references in templates, workflows, configs,
tests, and documentation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-31 10:28:25 -05:00

89 lines
2.5 KiB
Go

// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package recaptcha
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/json"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/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"`
}
// Verify calls Google Recaptcha API to verify token
func Verify(ctx context.Context, response string) (bool, error) {
post := url.Values{
"secret": {setting.Service.RecaptchaSecret},
"response": {response},
}
reqURL := strings.TrimSuffix(setting.Service.RecaptchaURL, "/") + "/api/siteverify"
// Basically a copy of http.PostForm, but with a context
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, 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)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return false, fmt.Errorf("Failed to read CAPTCHA response: %s", err)
}
var jsonResponse Response
err = json.Unmarshal(body, &jsonResponse)
if err != nil {
return false, fmt.Errorf("Failed to parse CAPTCHA response: %s", err)
}
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 is missing."
case "invalid-input-secret":
return "The secret parameter is invalid or malformed."
case "missing-input-response":
return "The response parameter is missing."
case "invalid-input-response":
return "The response parameter is invalid or malformed."
case "bad-request":
return "The request is invalid or malformed."
case "timeout-or-duplicate":
return "The response is no longer valid: either is too old or has been used previously."
}
return string(e)
}
// Error fulfills the error interface
func (e ErrorCode) Error() string {
return e.String()
}