lotus/cmd/lotus-fountain/recaptcha.go

74 lines
2.3 KiB
Go

// From https://github.com/lukasaron/recaptcha
// BLS-3 Licensed
// Copyright (c) 2020, Lukas Aron
// Modified by Kubuxu
package main
import (
"encoding/json"
"io"
"net/http"
"net/url"
"os"
"time"
)
// content type for communication with the verification server.
const (
contentType = "application/json"
)
// VerifyURL defines the endpoint which is called when a token needs to be verified.
var (
VerifyURL, _ = url.Parse("https://www.google.com/recaptcha/api/siteverify")
)
// Response defines the response format from the verification endpoint.
type Response struct {
Success bool `json:"success"` // status of the verification
TimeStamp time.Time `json:"challenge_ts"` // timestamp of the challenge load (ISO format)
HostName string `json:"hostname"` // the hostname of the site where the reCAPTCHA was solved
Score float64 `json:"score"` // the score for this request (0.0 - 1.0)
Action string `json:"action"` // the action name for this request
ErrorCodes []string `json:"error-codes"` // error codes
AndroidPackageName string `json:"apk_package_name"` // android related only
}
// VerifyToken function implements the basic logic of verification of ReCaptcha token that is usually created
// on the user site (front-end) and then sent to verify on the server side (back-end).
// To provide a successful verification process the secret key is required. Based on the security recommendations
// the key has to be passed as an environmental variable SECRET_KEY.
//
// Token parameter is required, however remoteIP is optional.
func VerifyToken(token, remoteIP string) (Response, error) {
resp := Response{}
if len(token) == 0 {
resp.ErrorCodes = []string{"no-token"}
return resp, nil
}
q := url.Values{}
q.Add("secret", os.Getenv("RECAPTCHA_SECRET_KEY"))
q.Add("response", token)
q.Add("remoteip", remoteIP)
var u *url.URL
{
verifyCopy := *VerifyURL
u = &verifyCopy
}
u.RawQuery = q.Encode()
r, err := http.Post(u.String(), contentType, nil)
if err != nil {
return resp, err
}
b, err := io.ReadAll(r.Body)
_ = r.Body.Close() // close immediately after reading finished
if err != nil {
return resp, err
}
return resp, json.Unmarshal(b, &resp)
}