diff options
Diffstat (limited to 'vendor/go.jolheiser.com/hcaptcha/hcaptcha.go')
-rw-r--r-- | vendor/go.jolheiser.com/hcaptcha/hcaptcha.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/vendor/go.jolheiser.com/hcaptcha/hcaptcha.go b/vendor/go.jolheiser.com/hcaptcha/hcaptcha.go new file mode 100644 index 0000000000..1f21f84008 --- /dev/null +++ b/vendor/go.jolheiser.com/hcaptcha/hcaptcha.go @@ -0,0 +1,105 @@ +package hcaptcha + +import ( + "context" + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" +) + +const verifyURL = "https://hcaptcha.com/siteverify" + +// Client is an hCaptcha client +type Client struct { + ctx context.Context + http *http.Client + + secret string +} + +// PostOptions are optional post form values +type PostOptions struct { + RemoteIP string + Sitekey string +} + +// ClientOption is a func to modify a new Client +type ClientOption func(*Client) + +// WithHTTP sets the http.Client of a Client +func WithHTTP(httpClient *http.Client) func(*Client) { + return func(hClient *Client) { + hClient.http = httpClient + } +} + +// WithContext sets the context.Context of a Client +func WithContext(ctx context.Context) func(*Client) { + return func(hClient *Client) { + hClient.ctx = ctx + } +} + +// New returns a new hCaptcha Client +func New(secret string, options ...ClientOption) (*Client, error) { + if strings.TrimSpace(secret) == "" { + return nil, ErrMissingInputSecret + } + + client := &Client{ + ctx: context.Background(), + http: http.DefaultClient, + secret: secret, + } + + for _, opt := range options { + opt(client) + } + + return client, nil +} + +// Verify checks the response against the hCaptcha API +func (c *Client) Verify(token string, opts PostOptions) (*Response, error) { + if strings.TrimSpace(token) == "" { + return nil, ErrMissingInputResponse + } + + post := url.Values{ + "secret": []string{c.secret}, + "response": []string{token}, + } + if strings.TrimSpace(opts.RemoteIP) != "" { + post.Add("remoteip", opts.RemoteIP) + } + if strings.TrimSpace(opts.Sitekey) != "" { + post.Add("sitekey", opts.Sitekey) + } + + // Basically a copy of http.PostForm, but with a context + req, err := http.NewRequestWithContext(c.ctx, http.MethodPost, verifyURL, strings.NewReader(post.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + resp, err := c.http.Do(req) + if err != nil { + return nil, err + } + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + var response *Response + if err := json.Unmarshal(body, &response); err != nil { + return nil, err + } + + return response, nil +} |