mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-26 14:46:24 -07:00
123 lines
3.4 KiB
Go
123 lines
3.4 KiB
Go
package posting
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/gochan-org/gochan/pkg/config"
|
|
"github.com/gochan-org/gochan/pkg/gcsql"
|
|
"github.com/gochan-org/gochan/pkg/gctemplates"
|
|
"github.com/gochan-org/gochan/pkg/gcutil"
|
|
"github.com/gochan-org/gochan/pkg/server"
|
|
"github.com/gochan-org/gochan/pkg/server/serverutil"
|
|
)
|
|
|
|
var (
|
|
ErrNoCaptchaToken = errors.New("missing required CAPTCHA")
|
|
ErrUnsupportedCaptcha = errors.New("unsupported captcha type set in configuration (currently only hcaptcha is supported)")
|
|
validCaptchaTypes = []string{"hcaptcha"}
|
|
)
|
|
|
|
type CaptchaResult struct {
|
|
Hostname string `json:"hostname"`
|
|
Credit bool `json:"credit"`
|
|
Success bool `json:"success"`
|
|
Timestamp time.Time `json:"challenge_ts"`
|
|
}
|
|
|
|
func InitCaptcha() {
|
|
var typeIsValid bool
|
|
captchaCfg := config.GetSiteConfig().Captcha
|
|
if !captchaCfg.UseCaptcha() {
|
|
return
|
|
}
|
|
for _, vType := range validCaptchaTypes {
|
|
if captchaCfg.Type == vType {
|
|
typeIsValid = true
|
|
}
|
|
}
|
|
if !typeIsValid {
|
|
gcutil.LogFatal().
|
|
Str("captchaType", captchaCfg.Type).
|
|
Msg("Unsupported captcha type set in configuration")
|
|
}
|
|
}
|
|
|
|
// submitCaptchaResponse parses the incoming captcha form values, submits them, and returns the results
|
|
func submitCaptchaResponse(request *http.Request) (bool, error) {
|
|
captchaCfg := config.GetSiteConfig().Captcha
|
|
if !captchaCfg.UseCaptcha() {
|
|
return true, nil // captcha isn't required, skip the test
|
|
}
|
|
threadid, _ := strconv.Atoi(request.PostFormValue("threadid"))
|
|
if captchaCfg.OnlyNeededForThreads && threadid > 0 {
|
|
return true, nil
|
|
}
|
|
|
|
var token string
|
|
switch captchaCfg.Type {
|
|
case "hcaptcha":
|
|
token = request.PostFormValue("h-captcha-response")
|
|
default:
|
|
|
|
}
|
|
|
|
if token == "" {
|
|
return false, ErrNoCaptchaToken
|
|
}
|
|
params := url.Values{
|
|
"secret": []string{captchaCfg.AccountSecret},
|
|
"response": []string{token},
|
|
}
|
|
resp, err := http.PostForm("https://hcaptcha.com/siteverify", params)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
var vals CaptchaResult
|
|
if err = json.NewDecoder(resp.Body).Decode(&vals); err != nil {
|
|
return false, err
|
|
}
|
|
return vals.Success, resp.Body.Close()
|
|
}
|
|
|
|
// ServeCaptcha handles requests to /captcha if the captcha is properly configured
|
|
func ServeCaptcha(writer http.ResponseWriter, request *http.Request) {
|
|
captchaCfg := config.GetSiteConfig().Captcha
|
|
if request.Method == "GET" && request.FormValue("needcaptcha") != "" {
|
|
fmt.Fprint(writer, captchaCfg.UseCaptcha())
|
|
return
|
|
}
|
|
errEv := gcutil.LogError(nil).
|
|
Str("IP", gcutil.GetRealIP(request))
|
|
defer func() {
|
|
errEv.Discard()
|
|
}()
|
|
wantsJSON := serverutil.IsRequestingJSON(request)
|
|
if !captchaCfg.UseCaptcha() {
|
|
server.ServeError(writer, "This site is not set up to require a CAPTCHA test", wantsJSON, nil)
|
|
return
|
|
}
|
|
if request.Method == "POST" {
|
|
result, err := submitCaptchaResponse(request)
|
|
if err != nil {
|
|
errEv.Err(err).Caller().Send()
|
|
server.ServeError(writer, "Error checking CAPTCHA results: "+err.Error(), wantsJSON, nil)
|
|
return
|
|
}
|
|
fmt.Println("Success:", result)
|
|
}
|
|
err := serverutil.MinifyTemplate(gctemplates.Captcha, map[string]any{
|
|
"boardConfig": config.GetBoardConfig(""),
|
|
"boards": gcsql.AllBoards,
|
|
"siteKey": captchaCfg.SiteKey,
|
|
}, writer, "text/html")
|
|
if err != nil {
|
|
errEv.Err(err).Caller().Send()
|
|
server.ServeError(writer, "Error serving CAPTCHA: "+err.Error(), wantsJSON, nil)
|
|
}
|
|
}
|