-
Notifications
You must be signed in to change notification settings - Fork 1
/
recaptcha.go
106 lines (86 loc) · 2.64 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
101
102
103
104
105
106
// Copyright 2021 Flamego. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package recaptcha
import (
"io"
"net/http"
"net/url"
"github.com/pkg/errors"
"github.com/flamego/flamego"
)
// VerifyURL is the API URL to verify user input.
type VerifyURL string
const (
// VerifyURLGoogle is the default API URL to verify reCAPTCHA requests.
VerifyURLGoogle VerifyURL = "https://www.google.com/recaptcha/api/siteverify"
// VerifyURLGlobal is API URL for the people who can't connect to the Google's server.
VerifyURLGlobal VerifyURL = "https://www.recaptcha.net/recaptcha/api/siteverify"
)
// Options contains options for both recaptcha.RecaptchaV2 and recaptcha.RecaptchaV3 middleware.
type Options struct {
// Client the HTTP client to make requests. The default is http.DefaultClient.
Client *http.Client
// Secret is the secret key to check user captcha codes. This field is required.
Secret string
VerifyURL
}
// V2 returns a middleware handler that injects recaptcha.RecaptchaV2
// into the request context, which is used for verifying reCAPTCHA V2 requests.
func V2(opts Options) flamego.Handler {
if opts.Client == nil {
opts.Client = http.DefaultClient
}
if opts.Secret == "" {
panic("recaptcha: empty secret")
}
if opts.VerifyURL == "" {
opts.VerifyURL = VerifyURLGoogle
}
return flamego.ContextInvoker(func(c flamego.Context) {
client := &recaptchaV2{
client: opts.Client,
secret: opts.Secret,
verifyURL: string(opts.VerifyURL),
}
c.MapTo(client, (*RecaptchaV2)(nil))
})
}
// V3 returns a middleware handler that injects recaptcha.RecaptchaV3
// into the request context, which is used for verifying reCAPTCHA V3 requests.
func V3(opts Options) flamego.Handler {
if opts.Client == nil {
opts.Client = http.DefaultClient
}
if opts.Secret == "" {
panic("recaptcha: empty secret")
}
if opts.VerifyURL == "" {
opts.VerifyURL = VerifyURLGoogle
}
return flamego.ContextInvoker(func(c flamego.Context) {
var client RecaptchaV3 = &recaptchaV3{
client: opts.Client,
secret: opts.Secret,
verifyURL: string(opts.VerifyURL),
}
c.Map(client)
})
}
func request(client *http.Client, endpoint, secret, response, remoteIP string) ([]byte, error) {
data := url.Values{
"secret": {secret},
"response": {response},
"remoteip": {remoteIP},
}
resp, err := client.PostForm(endpoint, data)
if err != nil {
return nil, errors.Wrapf(err, "POST %q", endpoint)
}
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "read response body")
}
return body, nil
}