Skip to content

Commit

Permalink
all: make the code example work (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
unknwon authored Mar 8, 2022
1 parent 3b9fd8c commit 1ff2634
Show file tree
Hide file tree
Showing 7 changed files with 338 additions and 79 deletions.
60 changes: 51 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,67 @@ The minimum requirement of Go is **1.16**.

## Getting started

```html
<!-- templates/home.tmpl -->
<html>
<head>
<script src="https://www.google.com/recaptcha/api.js"></script>
</head>
<body>
<script>
function onSubmit(token) {
document.getElementById("demo-form").submit();
}
</script>
<form id="demo-form" method="POST">
<button class="g-recaptcha"
data-sitekey="{{.SiteKey}}"
data-callback='onSubmit'
data-action='submit'>Submit</button>
</form>
</body>
</html>
```

```go
package main

import (
"fmt"
"net/http"

"github.com/flamego/flamego"
"github.com/flamego/recaptcha"
"github.com/flamego/hcaptcha"
"github.com/flamego/template"
)

func main() {
f := flamego.Classic()
f.Use(recaptcha.V2(recaptcha.Options{
Secret: "<YOUR_SECRET_HERE>",
VerifyURL: recaptcha.VerifyURLGlobal,
}))
f.Get("/verify", func(c flamego.Context, r recaptcha.RecaptchaV2) {
response, err := r.Verify(input)
if response.Success{
//...
f.Use(template.Templater())
f.Use(recaptcha.V3(
recaptcha.Options{
Secret: "<SECRET>",
VerifyURL: recaptcha.VerifyURLGoogle,
},
))
f.Get("/", func(t template.Template, data template.Data) {
data["SiteKey"] = "<SITE KEY>"
t.HTML(http.StatusOK, "home")
})
f.Post("/", func(w http.ResponseWriter, r *http.Request, re recaptcha.RecaptchaV3) {
token := r.PostFormValue("g-recaptcha-response")
resp, err := re.Verify(token)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(err.Error()))
return
} else if !resp.Success {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(fmt.Sprintf("Verification failed, error codes %v", resp.ErrorCodes)))
return
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Verified!"))
})
f.Run()
}
Expand Down
9 changes: 9 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
You need a [reCAPTCHA](https://www.google.com/recaptcha/about/) account to run this example.

```shell
$ go run main.go -site-key=<SITE KEY> -secret-key=<SECRET KEY>
[Flamego] Listening on 0.0.0.0:2830 (development)
...
```

Then, visit http://localhost:2830 to test the challenge.
72 changes: 72 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2022 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 main

import (
"flag"
"fmt"
"net/http"

"github.com/flamego/flamego"

"github.com/flamego/recaptcha"
)

func main() {
siteKey := flag.String("site-key", "", "The reCAPTCHA site key")
secretKey := flag.String("secret-key", "", "The reCAPTCHA secret key")
flag.Parse()

f := flamego.Classic()
f.Use(recaptcha.V3(
recaptcha.Options{
Secret: *secretKey,
VerifyURL: recaptcha.VerifyURLGoogle,
},
))

f.Get("/", func(w http.ResponseWriter) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
_, _ = w.Write([]byte(fmt.Sprintf(`
<html>
<head>
<script src="https://www.google.com/recaptcha/api.js"></script>
</head>
<body>
<script>
function onSubmit(token) {
document.getElementById("demo-form").submit();
}
</script>
<form id="demo-form" method="POST">
<button class="g-recaptcha"
data-sitekey="%s"
data-callback='onSubmit'
data-action='submit'>Submit</button>
</form>
</body>
</html>
`, *siteKey)))
})

f.Post("/", func(w http.ResponseWriter, r *http.Request, re recaptcha.RecaptchaV3) {
token := r.PostFormValue("g-recaptcha-response")
fmt.Println("token", token)
resp, err := re.Verify(token)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(err.Error()))
return
} else if !resp.Success {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(fmt.Sprintf("Verification failed, error codes %v", resp.ErrorCodes)))
return
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("Verified!"))
})

f.Run()
}
29 changes: 20 additions & 9 deletions recaptcha.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
package recaptcha

import (
"fmt"
"io"
"net/http"
"net/url"

"github.com/pkg/errors"

Expand All @@ -27,7 +27,9 @@ const (

// Options contains options for both recaptcha.RecaptchaV2 and recaptcha.RecaptchaV3 middleware.
type Options struct {
// Secret is the shared key between your site and reCAPTCHA. This field is required.
// 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
Expand All @@ -36,6 +38,10 @@ type Options struct {
// 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")
}
Expand All @@ -46,6 +52,7 @@ func V2(opts Options) flamego.Handler {

return flamego.ContextInvoker(func(c flamego.Context) {
client := &recaptchaV2{
client: opts.Client,
secret: opts.Secret,
verifyURL: string(opts.VerifyURL),
}
Expand All @@ -66,6 +73,7 @@ func V3(opts Options) flamego.Handler {

return flamego.ContextInvoker(func(c flamego.Context) {
var client RecaptchaV3 = &recaptchaV3{
client: opts.Client,
secret: opts.Secret,
verifyURL: string(opts.VerifyURL),
}
Expand All @@ -74,16 +82,19 @@ func V3(opts Options) flamego.Handler {
})
}

// request requests specific url and returns response.
func request(url, secret, response, remoteIP string) ([]byte, error) {
url = fmt.Sprintf("%s?secret=%s&response=%s&remoteIP=%s", url, secret, response, remoteIP)
res, err := http.Get(url)
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, "request %q", url)
return nil, errors.Wrapf(err, "POST %q", endpoint)
}
defer func() { _ = res.Body.Close() }()
defer func() { _ = resp.Body.Close() }()

body, err := io.ReadAll(res.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "read response body")
}
Expand Down
Loading

0 comments on commit 1ff2634

Please sign in to comment.