2023-04-24 16:51:55 +02:00
|
|
|
package auth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"codeberg.org/u1f320/pronouns.cc/backend/server"
|
|
|
|
"emperror.dev/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
const hcaptchaURL = "https://hcaptcha.com/siteverify"
|
|
|
|
|
|
|
|
type hcaptchaResponse struct {
|
|
|
|
Success bool `json:"success"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// verifyCaptcha verifies a captcha response.
|
|
|
|
func (s *Server) verifyCaptcha(ctx context.Context, response string) (ok bool, err error) {
|
|
|
|
vals := url.Values{
|
|
|
|
"response": []string{response},
|
|
|
|
"secret": []string{s.hcaptchaSecret},
|
|
|
|
"sitekey": []string{s.hcaptchaSitekey},
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "POST", hcaptchaURL, strings.NewReader(vals.Encode()))
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "creating request")
|
|
|
|
}
|
|
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
req.Header.Set("User-Agent", "pronouns.cc/"+server.Tag)
|
|
|
|
|
|
|
|
resp, err := http.DefaultClient.Do(req)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "sending request")
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 400 {
|
|
|
|
return false, errors.Sentinel("error status code")
|
|
|
|
}
|
|
|
|
b, err := io.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "reading body")
|
|
|
|
}
|
2023-05-06 15:53:07 +02:00
|
|
|
|
2023-04-24 16:51:55 +02:00
|
|
|
var hr hcaptchaResponse
|
|
|
|
err = json.Unmarshal(b, &hr)
|
|
|
|
if err != nil {
|
|
|
|
return false, errors.Wrap(err, "unmarshaling json")
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr.Success, nil
|
|
|
|
}
|