-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrecaptcha.go
100 lines (82 loc) · 1.96 KB
/
recaptcha.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package recaptcha
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
)
// Recaptcha holds all the necessary options to configure and verify the request.
type Recaptcha struct {
secret string
client *http.Client
version int
action string
score float64
}
// New returns a recaptcha service instance.
func New(secret string, options ...Option) (*Recaptcha, error) {
if secret == "" {
return nil, errMissingSecret
}
newRecaptcha := &Recaptcha{
secret: secret,
client: http.DefaultClient,
version: 3,
action: "",
score: 0.5,
}
for _, option := range options {
if err := option(newRecaptcha); err != nil {
return nil, err
}
}
return newRecaptcha, nil
}
// Verify the provided reCaptcha token depending on version.
func (c *Recaptcha) Verify(response string) error {
req, err := http.NewRequest(http.MethodPost, siteVerifyURL, nil)
if err != nil {
return err
}
// Add necessary request parameters.
q := req.URL.Query()
q.Add("secret", c.secret)
q.Add("response", response)
req.URL.RawQuery = q.Encode()
resp, err := c.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
var body siteVerifyResponse
if err = json.NewDecoder(resp.Body).Decode(&body); err != nil {
return err
}
if !body.Success {
return errRequestFailure
}
// Check additional response parameters applicable for V3.
if c.version == 3 {
if body.Score < c.score {
return errLowerScore
}
if body.Action != c.action {
return errMismatchAction
}
}
return nil
}
// GetRecaptchaToken from request body 'g-recaptcha-response' field.
func (c *Recaptcha) GetRecaptchaToken(r *http.Request) (string, error) {
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
return "", err
}
var body siteVerifyRequest
if err := json.Unmarshal(bodyBytes, &body); err != nil {
return "", err
}
// Restore request body to read more than once.
r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes))
return body.RecaptchaResponse, nil
}